diff options
Diffstat (limited to 'subsonic-android/src')
135 files changed, 0 insertions, 23812 deletions
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java deleted file mode 100644 index bfdc9eb9..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.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 github.daneren2005.dsub.activity; - -import github.daneren2005.dsub.R; -import android.os.Bundle; -import android.view.MotionEvent; -import github.daneren2005.dsub.fragments.DownloadFragment; -import android.app.Dialog; -import android.view.LayoutInflater; -import android.widget.EditText; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.util.Log; -import android.view.View; -import com.actionbarsherlock.view.MenuItem; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Util; -import java.util.LinkedList; -import java.util.List; - -public class DownloadActivity extends SubsonicActivity { - private static final String TAG = DownloadActivity.class.getSimpleName(); - private EditText playlistNameView; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.download_activity); - - if (findViewById(R.id.download_container) != null && savedInstanceState == null) { - currentFragment = new DownloadFragment(); - currentFragment.setPrimaryFragment(true); - getSupportFragmentManager().beginTransaction().add(R.id.download_container, currentFragment, currentFragment.getSupportTag() + "").commit(); - } - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId() == android.R.id.home) { - Intent i = new Intent(); - i.setClass(this, MainActivity.class); - i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - - @Override - public boolean onTouchEvent(MotionEvent me) { - if(currentFragment != null) { - return ((DownloadFragment)currentFragment).getGestureDetector().onTouchEvent(me); - } else { - return false; - } - } - - @Override - public void onBackPressed() { - if(onBackPressedSupport()) { - super.onBackPressed(); - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/EqualizerActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/EqualizerActivity.java deleted file mode 100644 index d9605fc5..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/activity/EqualizerActivity.java +++ /dev/null @@ -1,278 +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 github.daneren2005.dsub.activity; - -import java.util.HashMap; -import java.util.Map; - -import android.app.Activity; -import android.content.SharedPreferences; -import android.media.audiofx.Equalizer; -import android.os.Bundle; -import android.util.Log; -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 github.daneren2005.dsub.R; -import github.daneren2005.dsub.audiofx.EqualizerController; -import github.daneren2005.dsub.service.DownloadServiceImpl; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -/** - * Equalizer controls. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class EqualizerActivity extends Activity { - private static final String TAG = EqualizerActivity.class.getSimpleName(); - - private static final int MENU_GROUP_PRESET = 100; - - private final Map<Short, SeekBar> bars = new HashMap<Short, SeekBar>(); - private EqualizerController equalizerController; - private Equalizer equalizer; - private short masterLevel = 0; - - @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(); - - if(!equalizer.getEnabled()) { - equalizerController.release(); - } - } - - @Override - protected void onResume() { - super.onResume(); - equalizerController = DownloadServiceImpl.getInstance().getEqualizerController(); - equalizer = equalizerController.getEqualizer(); - } - - @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(false); - return true; - } - - private void setEqualizerEnabled(boolean enabled) { - SharedPreferences prefs = Util.getPreferences(EqualizerActivity.this); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_EQUALIZER_ON, enabled); - editor.commit(); - equalizer.setEnabled(enabled); - updateBars(true); - } - - private void updateBars(boolean changedEnabled) { - boolean isEnabled = equalizer.getEnabled(); - short minEQLevel = equalizer.getBandLevelRange()[0]; - short maxEQLevel = equalizer.getBandLevelRange()[1]; - for (Map.Entry<Short, SeekBar> entry : bars.entrySet()) { - short band = entry.getKey(); - SeekBar bar = entry.getValue(); - bar.setEnabled(isEnabled); - if(band >= (short)0) { - short setLevel; - if(changedEnabled) { - setLevel = (short)(equalizer.getBandLevel(band) - masterLevel); - bar.setProgress(equalizer.getBandLevel(band) - minEQLevel); - } else { - bar.setProgress(equalizer.getBandLevel(band) - minEQLevel); - setLevel = (short)(equalizer.getBandLevel(band) + masterLevel); - } - if(setLevel < minEQLevel) { - setLevel = minEQLevel; - } else if(setLevel > maxEQLevel) { - setLevel = maxEQLevel; - } - equalizer.setBandLevel(band, setLevel); - } else if(!isEnabled) { - bar.setProgress(-minEQLevel); - } - } - - if(!isEnabled) { - masterLevel = 0; - SharedPreferences prefs = Util.getPreferences(EqualizerActivity.this); - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel); - editor.commit(); - } - } - - private void initEqualizer() { - LinearLayout layout = (LinearLayout) findViewById(R.id.equalizer_layout); - - final short minEQLevel = equalizer.getBandLevelRange()[0]; - final short maxEQLevel = equalizer.getBandLevelRange()[1]; - - // Setup Pregain - SharedPreferences prefs = Util.getPreferences(this); - masterLevel = (short)prefs.getInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, 0); - initPregain(layout, minEQLevel, maxEQLevel); - - 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); - if(equalizer.getEnabled()) { - level = (short) (level - masterLevel); - } - 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, (short)(level + masterLevel)); - } - updateLevelText(levelTextView, level); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }); - layout.addView(bandBar); - } - } - - private void initPregain(LinearLayout layout, final short minEQLevel, final short maxEQLevel) { - 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("Master"); - - bars.put((short)-1, bar); - bar.setMax(maxEQLevel - minEQLevel); - bar.setProgress(masterLevel - minEQLevel); - bar.setEnabled(equalizer.getEnabled()); - updateLevelText(levelTextView, masterLevel); - - bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - masterLevel = (short) (progress + minEQLevel); - if (fromUser) { - SharedPreferences prefs = Util.getPreferences(EqualizerActivity.this); - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel); - editor.commit(); - for (short i = 0; i < equalizer.getNumberOfBands(); i++) { - short level = (short) ((bars.get(i).getProgress() + minEQLevel) + masterLevel); - equalizer.setBandLevel(i, level); - } - } - updateLevelText(levelTextView, masterLevel); - } - - @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/github/daneren2005/dsub/activity/HelpActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/HelpActivity.java deleted file mode 100644 index 6dc516bf..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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 github.daneren2005.dsub.R; -import github.daneren2005.dsub.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/github/daneren2005/dsub/activity/MainActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java deleted file mode 100644 index c077c87c..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java +++ /dev/null @@ -1,320 +0,0 @@ -package github.daneren2005.dsub.activity; - -import android.app.AlertDialog; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.view.Menu; -import android.support.v4.view.ViewPager; -import android.util.Log; -import android.view.View; -import android.widget.ImageButton; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.fragments.ChatFragment; -import github.daneren2005.dsub.fragments.MainFragment; -import github.daneren2005.dsub.fragments.SelectArtistFragment; -import github.daneren2005.dsub.fragments.SelectDirectoryFragment; -import github.daneren2005.dsub.fragments.SelectPlaylistFragment; -import github.daneren2005.dsub.fragments.SelectPodcastsFragment; -import github.daneren2005.dsub.fragments.SubsonicFragment; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.DownloadServiceImpl; -import github.daneren2005.dsub.updates.Updater; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.view.ChangeLog; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -public class MainActivity extends SubsonicActivity { - private static final String TAG = MainActivity.class.getSimpleName(); - private static boolean infoDialogDisplayed; - private ScheduledExecutorService executorService; - private View bottomBar; - private View coverArtView; - private TextView trackView; - private TextView artistView; - private ImageButton startButton; - private long lastBackPressTime = 0; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) { - stopService(new Intent(this, DownloadServiceImpl.class)); - finish(); - } else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) { - getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD); - Intent intent = new Intent(); - intent.setClass(this, DownloadActivity.class); - startActivity(intent); - } - setContentView(R.layout.main); - loadSettings(); - - bottomBar = findViewById(R.id.bottom_bar); - bottomBar.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - Intent intent = new Intent(); - intent.setClass(v.getContext(), DownloadActivity.class); - startActivity(intent); - } - }); - coverArtView = bottomBar.findViewById(R.id.album_art); - trackView = (TextView) bottomBar.findViewById(R.id.track_name); - artistView = (TextView) bottomBar.findViewById(R.id.artist_name); - - ImageButton previousButton = (ImageButton) findViewById(R.id.download_previous); - previousButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new SilentBackgroundTask<Void>(MainActivity.this) { - @Override - protected Void doInBackground() throws Throwable { - if(getDownloadService() == null) { - return null; - } - - getDownloadService().previous(); - return null; - } - - @Override - protected void done(Void result) { - update(); - } - }.execute(); - } - }); - - startButton = (ImageButton) findViewById(R.id.download_start); - startButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new SilentBackgroundTask<Void>(MainActivity.this) { - @Override - protected Void doInBackground() throws Throwable { - PlayerState state = getDownloadService().getPlayerState(); - if(state == PlayerState.STARTED) { - getDownloadService().pause(); - } else { - getDownloadService().start(); - } - - return null; - } - - @Override - protected void done(Void result) { - update(); - } - }.execute(); - } - }); - - ImageButton nextButton = (ImageButton) findViewById(R.id.download_next); - nextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new SilentBackgroundTask<Void>(MainActivity.this) { - @Override - protected Void doInBackground() throws Throwable { - if(getDownloadService() == null) { - return null; - } - - if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) { - getDownloadService().next(); - } - return null; - } - - @Override - protected void done(Void result) { - update(); - } - }.execute(); - } - }); - - viewPager = (ViewPager) findViewById(R.id.pager); - viewPager.setOffscreenPageLimit(4); - pagerAdapter = new TabPagerAdapter(this, viewPager); - viewPager.setAdapter(pagerAdapter); - viewPager.setOnPageChangeListener(pagerAdapter); - - addTab(R.string.button_bar_home, MainFragment.class, null); - addTab(R.string.button_bar_browse, SelectArtistFragment.class, null); - addTab(R.string.button_bar_playlists, SelectPlaylistFragment.class, null); - addTab(R.string.button_bar_podcasts, SelectPodcastsFragment.class, null); - SharedPreferences prefs = Util.getPreferences(this); - if(prefs.getBoolean(Constants.PREFERENCES_KEY_CHAT_ENABLED, true)) { - addTab(R.string.button_bar_chat, ChatFragment.class, null); - } - - getSupportActionBar().setDisplayHomeAsUpEnabled(false); - getSupportActionBar().setHomeButtonEnabled(false); - getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - } - - @Override - protected void onPostCreate(Bundle bundle) { - super.onPostCreate(bundle); - - showInfoDialog(); - checkUpdates(); - - ChangeLog changeLog = new ChangeLog(this, Util.getPreferences(this)); - if(changeLog.isFirstRun()) { - changeLog.getLogDialog().show(); - } - } - - @Override - public 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(); - } - }); - } - }; - - if(getIntent().hasExtra(Constants.INTENT_EXTRA_VIEW_ALBUM)) { - viewPager.setCurrentItem(1); - - int fragmentID = R.id.select_artist_layout; - if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID)) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID)); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PARENT_NAME)); - fragment.setArguments(args); - - pagerAdapter.queueFragment(fragment, R.id.select_artist_layout); - fragmentID = fragment.getRootId(); - } - - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID)); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME)); - fragment.setArguments(args); - - pagerAdapter.queueFragment(fragment, fragmentID); - getIntent().removeExtra(Constants.INTENT_EXTRA_VIEW_ALBUM); - } - - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS); - } - - @Override - public void onPause() { - super.onPause(); - executorService.shutdown(); - } - - @Override - public void onBackPressed() { - if(onBackPressedSupport()) { - if(lastBackPressTime < (System.currentTimeMillis() - 4000)) { - lastBackPressTime = System.currentTimeMillis(); - Util.toast(this, R.string.main_back_confirm); - } else { - finish(); - } - } - } - - private void update() { - if (getDownloadService() == null) { - return; - } - - DownloadFile current = getDownloadService().getCurrentPlaying(); - if(current == null) { - trackView.setText("Title"); - artistView.setText("Artist"); - getImageLoader().loadImage(coverArtView, null, false, false); - return; - } - - MusicDirectory.Entry song = current.getSong(); - trackView.setText(song.getTitle()); - artistView.setText(song.getArtist()); - getImageLoader().loadImage(coverArtView, song, false, false); - int[] attrs = new int[] {(getDownloadService().getPlayerState() == PlayerState.STARTED) ? R.attr.media_button_pause : R.attr.media_button_start}; - TypedArray typedArray = this.obtainStyledAttributes(attrs); - Drawable drawable = typedArray.getDrawable(0); - startButton.setImageDrawable(drawable); - typedArray.recycle(); - } - - public void checkUpdates() { - try { - String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; - int ver = Integer.parseInt(version.replace(".", "")); - Updater updater = new Updater(ver); - updater.checkUpdates(this); - } - catch(Exception e) { - - } - } - - 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(); - } - - if (!prefs.contains(Constants.PREFERENCES_KEY_OFFLINE)) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, false); - - editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + 1, "Demo Server"); - editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + 1, "http://demo.subsonic.org"); - editor.putString(Constants.PREFERENCES_KEY_USERNAME + 1, "android-guest"); - editor.putString(Constants.PREFERENCES_KEY_PASSWORD + 1, "guest"); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - editor.commit(); - } - if(!prefs.contains(Constants.PREFERENCES_KEY_SERVER_COUNT)) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 3); - editor.commit(); - } - } - - private void showInfoDialog() { - if (!infoDialogDisplayed) { - infoDialogDisplayed = true; - Log.i(TAG, Util.getRestUrl(this, null)); - if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) { - Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text); - } - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java deleted file mode 100644 index 15d0c6a6..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.activity; - -import android.app.Activity; -import android.app.SearchManager; -import android.content.Intent; -import android.os.Bundle; -import android.provider.SearchRecentSuggestions; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.provider.DSubSearchProvider; - -/** - * 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, DSubSearchProvider.AUTHORITY, - DSubSearchProvider.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/github/daneren2005/dsub/activity/SearchActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java deleted file mode 100644 index aeddcf4f..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.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 github.daneren2005.dsub.activity; - -import github.daneren2005.dsub.R; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; -import github.daneren2005.dsub.fragments.SearchFragment; -import github.daneren2005.dsub.util.Constants; -import com.actionbarsherlock.view.MenuItem; - -public class SearchActivity extends SubsonicActivity { - private static final String TAG = SearchActivity.class.getSimpleName(); - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.download_activity); - - if (findViewById(R.id.download_container) != null && savedInstanceState == null) { - currentFragment = new SearchFragment(); - currentFragment.setPrimaryFragment(true); - getSupportFragmentManager().beginTransaction().add(R.id.download_container, currentFragment, currentFragment.getSupportTag() + "").commit(); - } - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - if(currentFragment != null && currentFragment instanceof SearchFragment) { - 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) { - ((SearchFragment)currentFragment).search(query, autoplay); - } else { - ((SearchFragment)currentFragment).populateList(); - if (requestsearch) { - onSearchRequested(); - } - } - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId() == android.R.id.home) { - Intent i = new Intent(); - i.setClass(this, MainActivity.class); - i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - - public void onSupportNewIntent(Intent intent) { - onNewIntent(intent); - } - - @Override - public void onBackPressed() { - if(onBackPressedSupport()) { - super.onBackPressed(); - } - } -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SettingsActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SettingsActivity.java deleted file mode 100644 index fc56281e..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/activity/SettingsActivity.java +++ /dev/null @@ -1,539 +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 github.daneren2005.dsub.activity; - -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Bundle; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceCategory; -import android.preference.PreferenceScreen; -import android.provider.SearchRecentSuggestions; -import android.text.InputType; -import android.util.Log; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.provider.DSubSearchProvider; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.DownloadServiceImpl; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.view.ErrorDialog; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -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 maxVideoBitrateWifi; - private ListPreference maxVideoBitrateMobile; - private ListPreference networkTimeout; - private EditTextPreference cacheSize; - private EditTextPreference cacheLocation; - private ListPreference preloadCountWifi; - private ListPreference preloadCountMobile; - private EditTextPreference randomSize; - private ListPreference tempLoss; - private EditTextPreference bufferLength; - private Preference addServerPreference; - private PreferenceCategory serversCategory; - private EditTextPreference chatRefreshRate; - private ListPreference videoPlayer; - - private int serverCount = 3; - private SharedPreferences settings; - - @Override - public void onCreate(Bundle savedInstanceState) { - applyTheme(); - 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); - maxVideoBitrateWifi = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_WIFI); - maxVideoBitrateMobile = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_MOBILE); - networkTimeout = (ListPreference) findPreference(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT); - cacheSize = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_CACHE_SIZE); - cacheLocation = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_CACHE_LOCATION); - preloadCountWifi = (ListPreference) findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT_WIFI); - preloadCountMobile = (ListPreference) findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT_MOBILE); - randomSize = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_RANDOM_SIZE); - tempLoss = (ListPreference) findPreference(Constants.PREFERENCES_KEY_TEMP_LOSS); - bufferLength = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_BUFFER_LENGTH); - addServerPreference = (Preference) findPreference(Constants.PREFERENCES_KEY_SERVER_ADD); - serversCategory = (PreferenceCategory) findPreference(Constants.PREFERENCES_KEY_SERVER_KEY); - chatRefreshRate = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_CHAT_REFRESH); - videoPlayer = (ListPreference) findPreference(Constants.PREFERENCES_KEY_VIDEO_PLAYER); - - settings = Util.getPreferences(this); - serverCount = settings.getInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 3); - - findPreference("clearSearchHistory").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - SearchRecentSuggestions suggestions = new SearchRecentSuggestions(SettingsActivity.this, DSubSearchProvider.AUTHORITY, DSubSearchProvider.MODE); - suggestions.clearHistory(); - Util.toast(SettingsActivity.this, R.string.settings_search_history_cleared); - return false; - } - }); - findPreference("clearCache").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - Util.confirmDialog(SettingsActivity.this, R.string.common_delete, "cache", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LoadingTask<Void>(SettingsActivity.this, false) { - @Override - protected Void doInBackground() throws Throwable { - FileUtil.deleteMusicDirectory(SettingsActivity.this); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(SettingsActivity.this, R.string.settings_cache_clear_complete); - } - - @Override - protected void error(Throwable error) { - Util.toast(SettingsActivity.this, getErrorMessage(error), false); - } - }.execute(); - } - }); - return false; - } - }); - - addServerPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - serverCount++; - String instance = String.valueOf(serverCount); - - Preference addServerPreference = findPreference(Constants.PREFERENCES_KEY_SERVER_ADD); - serversCategory.removePreference(addServerPreference); - serversCategory.addPreference(addServer(serverCount)); - serversCategory.addPreference(addServerPreference); - - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, serverCount); - editor.commit(); - - serverSettings.put(instance, new ServerSettings(instance)); - - return true; - } - }); - - serversCategory.removePreference(addServerPreference); - for (int i = 1; i <= serverCount; i++) { - String instance = String.valueOf(i); - serversCategory.addPreference(addServer(i)); - serverSettings.put(instance, new ServerSettings(instance)); - } - serversCategory.addPreference(addServerPreference); - - 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, "")); - } - else if (Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION.equals(key)){ - DownloadService downloadService = DownloadServiceImpl.getInstance(); - downloadService.setSleepTimerDuration(Integer.parseInt(sharedPreferences.getString(key, "60"))); - } - - scheduleBackup(); - } - - private void scheduleBackup() { - try { - Class managerClass = Class.forName("android.app.backup.BackupManager"); - Constructor managerConstructor = managerClass.getConstructor(Context.class); - Object manager = managerConstructor.newInstance(this); - Method m = managerClass.getMethod("dataChanged"); - m.invoke(manager); - Log.d(TAG, "Backup requested"); - } catch(ClassNotFoundException e) { - Log.d(TAG, "No backup manager found"); - } catch(Throwable t) { - Log.d(TAG, "Scheduling backup failed " + t); - t.printStackTrace(); - } - } - - private void update() { - if (testingConnection) { - return; - } - - theme.setSummary(theme.getEntry()); - maxBitrateWifi.setSummary(maxBitrateWifi.getEntry()); - maxBitrateMobile.setSummary(maxBitrateMobile.getEntry()); - maxVideoBitrateWifi.setSummary(maxVideoBitrateWifi.getEntry()); - maxVideoBitrateMobile.setSummary(maxVideoBitrateMobile.getEntry()); - networkTimeout.setSummary(networkTimeout.getEntry()); - cacheSize.setSummary(cacheSize.getText()); - cacheLocation.setSummary(cacheLocation.getText()); - preloadCountWifi.setSummary(preloadCountWifi.getEntry()); - preloadCountMobile.setSummary(preloadCountMobile.getEntry()); - randomSize.setSummary(randomSize.getText()); - tempLoss.setSummary(tempLoss.getEntry()); - bufferLength.setSummary(bufferLength.getText() + " seconds"); - chatRefreshRate.setSummary(chatRefreshRate.getText()); - videoPlayer.setSummary(videoPlayer.getEntry()); - for (ServerSettings ss : serverSettings.values()) { - ss.update(); - } - } - - private PreferenceScreen addServer(final int instance) { - final PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(this); - screen.setTitle(R.string.settings_server_unused); - screen.setKey(Constants.PREFERENCES_KEY_SERVER_KEY + instance); - - final EditTextPreference serverNamePreference = new EditTextPreference(this); - serverNamePreference.setKey(Constants.PREFERENCES_KEY_SERVER_NAME + instance); - serverNamePreference.setDefaultValue(getResources().getString(R.string.settings_server_unused)); - serverNamePreference.setTitle(R.string.settings_server_name); - - if (serverNamePreference.getText() == null) { - serverNamePreference.setText(getResources().getString(R.string.settings_server_unused)); - } - - serverNamePreference.setSummary(serverNamePreference.getText()); - - final EditTextPreference serverUrlPreference = new EditTextPreference(this); - serverUrlPreference.setKey(Constants.PREFERENCES_KEY_SERVER_URL + instance); - serverUrlPreference.getEditText().setInputType(InputType.TYPE_TEXT_VARIATION_URI); - serverUrlPreference.setDefaultValue("http://yourhost"); - serverUrlPreference.setTitle(R.string.settings_server_address); - - if (serverUrlPreference.getText() == null) { - serverUrlPreference.setText("http://yourhost"); - } - - serverUrlPreference.setSummary(serverUrlPreference.getText()); - - screen.setSummary(serverUrlPreference.getText()); - - final EditTextPreference serverUsernamePreference = new EditTextPreference(this); - serverUsernamePreference.setKey(Constants.PREFERENCES_KEY_USERNAME + instance); - serverUsernamePreference.setTitle(R.string.settings_server_username); - - final EditTextPreference serverPasswordPreference = new EditTextPreference(this); - serverPasswordPreference.setKey(Constants.PREFERENCES_KEY_PASSWORD + instance); - serverPasswordPreference.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); - serverPasswordPreference.setSummary("***"); - serverPasswordPreference.setTitle(R.string.settings_server_password); - - final Preference serverOpenBrowser = new Preference(this); - serverOpenBrowser.setKey(Constants.PREFERENCES_KEY_OPEN_BROWSER); - serverOpenBrowser.setPersistent(false); - serverOpenBrowser.setTitle(R.string.settings_server_open_browser); - serverOpenBrowser.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - openInBrowser(instance); - return true; - } - }); - - Preference serverRemoveServerPreference = new Preference(this); - serverRemoveServerPreference.setKey(Constants.PREFERENCES_KEY_SERVER_REMOVE + instance); - serverRemoveServerPreference.setPersistent(false); - serverRemoveServerPreference.setTitle(R.string.settings_servers_remove); - - serverRemoveServerPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - Util.confirmDialog(SettingsActivity.this, R.string.common_delete, screen.getTitle().toString(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // Reset values to null so when we ask for them again they are new - serverNamePreference.setText(null); - serverUrlPreference.setText(null); - serverUsernamePreference.setText(null); - serverPasswordPreference.setText(null); - - int activeServer = Util.getActiveServer(SettingsActivity.this); - for (int i = instance; i <= serverCount; i++) { - Util.removeInstanceName(SettingsActivity.this, i, activeServer); - } - - serverCount--; - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, serverCount); - editor.commit(); - - serversCategory.removePreference(screen); - screen.getDialog().dismiss(); - } - }); - - return true; - } - }); - - Preference serverTestConnectionPreference = new Preference(this); - serverTestConnectionPreference.setKey(Constants.PREFERENCES_KEY_TEST_CONNECTION + instance); - serverTestConnectionPreference.setPersistent(false); - serverTestConnectionPreference.setTitle(R.string.settings_test_connection_title); - serverTestConnectionPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - testConnection(instance); - return false; - } - }); - - screen.addPreference(serverNamePreference); - screen.addPreference(serverUrlPreference); - screen.addPreference(serverUsernamePreference); - screen.addPreference(serverPasswordPreference); - screen.addPreference(serverRemoveServerPreference); - screen.addPreference(serverTestConnectionPreference); - screen.addPreference(serverOpenBrowser); - - return screen; - } - - private void applyTheme() { - String activeTheme = Util.getTheme(this); - if ("dark".equals(activeTheme)) { - setTheme(R.style.Theme_DSub_Dark); - } else if ("black".equals(activeTheme)) { - setTheme(R.style.Theme_DSub_Black); - } else if ("light".equals(activeTheme)) { - setTheme(R.style.Theme_DSub_Light); - } else if ("dark_fullscreen".equals(activeTheme)) { - setTheme(R.style.Theme_DSub_Dark_Fullscreen); - } else if ("black_fullscreen".equals(activeTheme)) { - setTheme(R.style.Theme_DSub_Black_Fullscreen); - } else if ("light_fullscreen".equals(activeTheme)) { - setTheme(R.style.Theme_DSub_Light_Fullscreen); - } else if("holo".equals(activeTheme)) { - setTheme(R.style.Theme_DSub_Holo); - } else if("holo_fullscreen".equals(activeTheme)) { - setTheme(R.style.Theme_DSub_Holo_Fullscreen); - }else { - setTheme(R.style.Theme_DSub_Holo); - } - } - - private void setHideMedia(boolean hide) { - File nomediaDir = new File(FileUtil.getSubsonicDirectory(), ".nomedia"); - if (hide && !nomediaDir.exists()) { - try { - if (!nomediaDir.createNewFile()) { - Log.w(TAG, "Failed to create " + nomediaDir); - } - } catch(Exception e) { - 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) { - LoadingTask<Boolean> task = new LoadingTask<Boolean>(this) { - 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 void openInBrowser(final int instance) { - SharedPreferences prefs = Util.getPreferences(this); - String url = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null); - Uri uriServer = Uri.parse(url); - - Intent browserIntent = new Intent(Intent.ACTION_VIEW, uriServer); - startActivity(browserIntent); - } - - 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("@") || 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()); - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java deleted file mode 100644 index d8158f7d..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java +++ /dev/null @@ -1,641 +0,0 @@ -package github.daneren2005.dsub.activity;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.media.AudioManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.ViewPager;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.Spinner;
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.ActionBar.Tab;
-import com.actionbarsherlock.app.ActionBar.TabListener;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
-import com.actionbarsherlock.app.SherlockFragment;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuItem;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.fragments.SubsonicFragment;
-import github.daneren2005.dsub.service.DownloadService;
-import github.daneren2005.dsub.service.DownloadServiceImpl;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.ImageLoader;
-import github.daneren2005.dsub.util.Util;
-import java.io.File;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-public class SubsonicActivity extends SherlockFragmentActivity implements OnItemSelectedListener {
- private static final String TAG = SubsonicActivity.class.getSimpleName();
- private static ImageLoader IMAGE_LOADER;
- protected static String theme;
- private boolean destroyed = false;
- protected TabPagerAdapter pagerAdapter;
- protected ViewPager viewPager;
- protected List<SubsonicFragment> backStack = new ArrayList<SubsonicFragment>();
- protected SubsonicFragment currentFragment;
- Spinner actionBarSpinner;
- ArrayAdapter<CharSequence> spinnerAdapter;
-
- @Override
- protected void onCreate(Bundle bundle) {
- setUncaughtExceptionHandler();
- applyTheme();
- super.onCreate(bundle);
- startService(new Intent(this, DownloadServiceImpl.class));
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- View actionbar = getLayoutInflater().inflate(R.layout.actionbar_spinner, null);
- actionBarSpinner = (Spinner)actionbar.findViewById(R.id.spinner);
- spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
- spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- actionBarSpinner.setOnItemSelectedListener(this);
- actionBarSpinner.setAdapter(spinnerAdapter);
-
- getSupportActionBar().setCustomView(actionbar);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Util.registerMediaButtonEventReceiver(this);
-
- // Make sure to update theme
- if (theme != null && !theme.equals(Util.getTheme(this))) {
- restart();
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- destroyed = true;
- getImageLoader().clear();
- }
-
- @Override
- public void finish() {
- super.finish();
- Util.disablePendingTransition(this);
- }
-
- @Override
- public void onSaveInstanceState(Bundle savedInstanceState) {
- super.onSaveInstanceState(savedInstanceState);
- if(viewPager == null) {
- String[] ids = new String[backStack.size() + 1];
- ids[0] = currentFragment.getTag();
- int i = 1;
- for(SubsonicFragment frag: backStack) {
- ids[i] = frag.getTag();
- i++;
- }
- savedInstanceState.putStringArray(Constants.MAIN_BACK_STACK, ids);
- savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE, backStack.size() + 1);
- } else {
- pagerAdapter.onSaveInstanceState(savedInstanceState);
- }
- }
- @Override
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- if(viewPager == null) {
- super.onRestoreInstanceState(savedInstanceState);
- int size = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_SIZE);
- String[] ids = savedInstanceState.getStringArray(Constants.MAIN_BACK_STACK);
- FragmentManager fm = getSupportFragmentManager();
- currentFragment = (SubsonicFragment)fm.findFragmentByTag(ids[0]);
- currentFragment.setPrimaryFragment(true);
- invalidateOptionsMenu();
- for(int i = 1; i < size; i++) {
- SubsonicFragment frag = (SubsonicFragment)fm.findFragmentByTag(ids[i]);
- backStack.add(frag);
- }
- recreateSpinner();
- } else {
- pagerAdapter.onRestoreInstanceState(savedInstanceState);
- super.onRestoreInstanceState(savedInstanceState);
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- com.actionbarsherlock.view.MenuInflater menuInflater = getSupportMenuInflater();
- if(pagerAdapter != null) {
- pagerAdapter.onCreateOptionsMenu(menu, menuInflater);
- } else if(currentFragment != null) {
- currentFragment.onCreateOptionsMenu(menu, menuInflater);
- }
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- if(pagerAdapter != null) {
- return pagerAdapter.onOptionsItemSelected(item);
- } else if(currentFragment != null) {
- return currentFragment.onOptionsItemSelected(item);
- }
- return true;
- }
-
- @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 setTitle(CharSequence title) {
- super.setTitle(title);
- if(pagerAdapter != null) {
- pagerAdapter.recreateSpinner();
- } else {
- recreateSpinner();
- }
- }
- public void setSubtitle(CharSequence title) {
- getSupportActionBar().setSubtitle(title);
- }
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- int top = spinnerAdapter.getCount() - 1;
- if(position < top) {
- for(int i = top; i > position; i--) {
- if(pagerAdapter != null) {
- pagerAdapter.removeCurrent();
- } else {
- removeCurrent();
- }
- }
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
-
- }
-
- public boolean onBackPressedSupport() {
- if(pagerAdapter != null) {
- return pagerAdapter.onBackPressed();
- } else {
- if(backStack.size() > 0) {
- removeCurrent();
- return false;
- } else {
- return true;
- }
- }
- }
-
- public void replaceFragment(SubsonicFragment fragment, int id, int tag) {
- if(pagerAdapter != null) {
- pagerAdapter.replaceCurrent(fragment, id, tag);
- } else {
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
- }
- backStack.add(currentFragment);
-
- currentFragment = fragment;
- currentFragment.setPrimaryFragment(true);
- invalidateOptionsMenu();
-
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.add(id, fragment, tag + "");
- trans.commit();
- recreateSpinner();
- }
- }
- private void removeCurrent() {
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
- }
- Fragment oldFrag = (Fragment)currentFragment;
-
- currentFragment = (SubsonicFragment) backStack.remove(backStack.size() - 1);
- currentFragment.setPrimaryFragment(true);
- invalidateOptionsMenu();
-
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.remove(oldFrag);
- trans.commit();
- recreateSpinner();
- }
-
- private void recreateSpinner() {
- if(backStack.size() > 0) {
- spinnerAdapter.clear();
- for(int i = 0; i < backStack.size(); i++) {
- spinnerAdapter.add(backStack.get(i).getTitle());
- }
- spinnerAdapter.add(currentFragment.getTitle());
- spinnerAdapter.notifyDataSetChanged();
- actionBarSpinner.setSelection(spinnerAdapter.getCount() - 1);
- getSupportActionBar().setDisplayShowCustomEnabled(true);
- } else {
- getSupportActionBar().setDisplayShowCustomEnabled(false);
- }
- }
-
- protected void addTab(int titleRes, Class fragmentClass, Bundle args) {
- pagerAdapter.addTab(getString(titleRes), fragmentClass, args);
- }
- protected void addTab(CharSequence title, Class fragmentClass, Bundle args) {
- pagerAdapter.addTab(title, fragmentClass, args);
- }
-
- protected void restart() {
- Intent intent = new Intent(this, this.getClass());
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtras(getIntent());
- Util.startActivityWithoutTransition(this, intent);
- }
-
- private void applyTheme() {
- theme = Util.getTheme(this);
- if ("dark".equals(theme)) {
- setTheme(R.style.Theme_DSub_Dark);
- } else if ("black".equals(theme)) {
- setTheme(R.style.Theme_DSub_Black);
- } else if ("light".equals(theme)) {
- setTheme(R.style.Theme_DSub_Light);
- } else if ("dark_fullscreen".equals(theme)) {
- setTheme(R.style.Theme_DSub_Dark_Fullscreen);
- } else if ("black_fullscreen".equals(theme)) {
- setTheme(R.style.Theme_DSub_Black_Fullscreen);
- } else if ("light_fullscreen".equals(theme)) {
- setTheme(R.style.Theme_DSub_Light_Fullscreen);
- } else if("holo".equals(theme)) {
- setTheme(R.style.Theme_DSub_Holo);
- } else if("holo_fullscreen".equals(theme)) {
- setTheme(R.style.Theme_DSub_Holo_Fullscreen);
- }else {
- setTheme(R.style.Theme_DSub_Holo);
- }
- }
-
- public boolean isDestroyed() {
- return destroyed;
- }
-
- public synchronized ImageLoader getImageLoader() {
- if (IMAGE_LOADER == null) {
- IMAGE_LOADER = new ImageLoader(this);
- }
- return IMAGE_LOADER;
- }
- public synchronized static ImageLoader getStaticImageLoader(Context context) {
- if (IMAGE_LOADER == null) {
- IMAGE_LOADER = new ImageLoader(context);
- }
- return IMAGE_LOADER;
- }
-
- 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();
- }
-
- public ViewPager getViewPager() {
- return viewPager;
- }
- public TabPagerAdapter getPagerAdapter() {
- return pagerAdapter;
- }
-
- public static String getThemeName() {
- return theme;
- }
-
- private void setUncaughtExceptionHandler() {
- Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
- if (!(handler instanceof SubsonicActivity.SubsonicUncaughtExceptionHandler)) {
- Thread.setDefaultUncaughtExceptionHandler(new SubsonicActivity.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("github.daneren2005.dsub", 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);
- }
-
- }
- }
- }
-
- public class TabPagerAdapter extends FragmentPagerAdapter implements TabListener, ViewPager.OnPageChangeListener {
- private SherlockFragmentActivity activity;
- private ViewPager pager;
- private ActionBar actionBar;
- private SubsonicFragment currentFragment;
- private List<TabInfo> tabs = new ArrayList<TabInfo>();
- private List<List<SubsonicFragment>> frags = new ArrayList<List<SubsonicFragment>>();
- private List<QueuedFragment> queue = new ArrayList<QueuedFragment>();
- private int currentPosition;
-
- public TabPagerAdapter(SherlockFragmentActivity activity, ViewPager pager) {
- super(activity.getSupportFragmentManager());
- this.activity = activity;
- this.actionBar = activity.getSupportActionBar();
- this.pager = pager;
- this.currentPosition = 0;
- }
-
- @Override
- public Fragment getItem(int i) {
- final TabInfo tabInfo = tabs.get(i);
- SubsonicFragment frag = (SubsonicFragment) Fragment.instantiate(activity, tabInfo.fragmentClass.getName(), tabInfo.args);
- List<SubsonicFragment> fragStack = new ArrayList<SubsonicFragment>();
- fragStack.add(frag);
- while(i > frags.size()) {
- frags.add(null);
- }
- if(i == frags.size()) {
- frags.add(i, fragStack);
- } else {
- frags.set(i, fragStack);
- }
- if(currentFragment == null || currentPosition == i) {
- currentFragment = frag;
- currentFragment.setPrimaryFragment(true);
- }
- return frag;
- }
-
- @Override
- public int getCount() {
- return tabs.size();
- }
-
- public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
- if(currentFragment != null) {
- currentFragment.onCreateOptionsMenu(menu, menuInflater);
-
- for(QueuedFragment addFragment: queue) {
- replaceFragment(addFragment.fragment, addFragment.id, currentFragment.getSupportTag());
- currentFragment = addFragment.fragment;
- }
- currentFragment.setPrimaryFragment(true);
- queue.clear();
- }
- }
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- if(currentFragment != null) {
- return currentFragment.onOptionsItemSelected(item);
- } else {
- return false;
- }
- }
-
- public void onTabSelected(Tab tab, FragmentTransaction ft) {
- TabInfo tabInfo = (TabInfo) tab.getTag();
- for (int i = 0; i < tabs.size(); i++) {
- if ( tabs.get(i) == tabInfo ) {
- pager.setCurrentItem(i);
- break;
- }
- }
- }
-
- public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
-
- public void onTabReselected(Tab tab, FragmentTransaction ft) {}
-
- public void onPageScrollStateChanged(int arg0) {}
-
- public void onPageScrolled(int arg0, float arg1, int arg2) {}
-
- public void onPageSelected(int position) {
- currentPosition = position;
- actionBar.setSelectedNavigationItem(position);
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
- }
- if(position <= frags.size()) {
- List<SubsonicFragment> fragStack = frags.get(position);
- currentFragment = fragStack.get(fragStack.size() - 1);
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(true);
- }
- activity.invalidateOptionsMenu();
- recreateSpinner();
- }
- }
-
- public void addTab(CharSequence title, Class fragmentClass, Bundle args) {
- final TabInfo tabInfo = new TabInfo(fragmentClass, args);
-
- Tab tab = actionBar.newTab();
- tab.setText(title);
- tab.setTabListener(this);
- tab.setTag(tabInfo);
-
- tabs.add(tabInfo);
-
- actionBar.addTab(tab);
- notifyDataSetChanged();
- }
- public void queueFragment(SubsonicFragment fragment, int id) {
- QueuedFragment frag = new QueuedFragment();
- frag.fragment = fragment;
- frag.id = id;
- queue.add(frag);
- }
- public void replaceCurrent(SubsonicFragment fragment, int id, int tag) {
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
- }
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- fragStack.add(fragment);
-
- currentFragment = fragment;
- currentFragment.setPrimaryFragment(true);
- activity.invalidateOptionsMenu();
-
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.add(id, fragment, tag + "");
- trans.commit();
- recreateSpinner();
- }
-
- public void removeCurrent() {
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
- }
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- Fragment oldFrag = (Fragment)fragStack.remove(fragStack.size() - 1);
-
- currentFragment = fragStack.get(fragStack.size() - 1);
- currentFragment.setPrimaryFragment(true);
- activity.invalidateOptionsMenu();
-
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.remove(oldFrag);
- trans.commit();
- }
-
- public boolean onBackPressed() {
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- if(fragStack.size() > 1) {
- removeCurrent();
- recreateSpinner();
- return false;
- } else {
- if(currentPosition == 0) {
- return true;
- } else {
- viewPager.setCurrentItem(0);
- return false;
- }
- }
- }
-
- private void recreateSpinner() {
- if(frags.isEmpty()) {
- return;
- }
-
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- if(fragStack.size() > 1) {
- spinnerAdapter.clear();
- for(int i = 0; i < fragStack.size(); i++) {
- SubsonicFragment frag = fragStack.get(i);
- spinnerAdapter.add(frag.getTitle());
- }
- spinnerAdapter.notifyDataSetChanged();
- actionBarSpinner.setSelection(spinnerAdapter.getCount() - 1);
- actionBar.setDisplayShowCustomEnabled(true);
- } else {
- actionBar.setDisplayShowCustomEnabled(false);
- }
- }
-
- public void invalidate() {
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- for (int i = 0; i < frags.size(); i++) {
- List<SubsonicFragment> fragStack = frags.get(i);
-
- for(int j = fragStack.size() - 1; j > 0; j--) {
- SubsonicFragment oldFrag = fragStack.remove(j);
- trans.remove((Fragment)oldFrag);
- }
-
- SubsonicFragment frag = (SubsonicFragment)fragStack.get(0);
- frag.invalidate();
- }
- trans.commit();
- }
-
- public void onSaveInstanceState(Bundle savedInstanceState) {
- for(int i = 0; i < frags.size(); i++) {
- List<SubsonicFragment> fragStack = frags.get(i);
- String[] ids = new String[fragStack.size()];
-
- for(int j = 0; j < fragStack.size(); j++) {
- ids[j] = fragStack.get(j).getTag();
- }
- savedInstanceState.putStringArray(Constants.MAIN_BACK_STACK + i, ids);
- savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE + i, fragStack.size());
- }
- savedInstanceState.putInt(Constants.MAIN_BACK_STACK_TABS, frags.size());
- savedInstanceState.putInt(Constants.MAIN_BACK_STACK_POSITION, currentPosition);
- }
-
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- int tabCount = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_TABS);
- FragmentManager fm = activity.getSupportFragmentManager();
- for(int i = 0; i < tabCount; i++) {
- int stackSize = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_SIZE + i);
- String[] ids = savedInstanceState.getStringArray(Constants.MAIN_BACK_STACK + i);
- List<SubsonicFragment> fragStack = new ArrayList<SubsonicFragment>();
-
- for(int j = 0; j < stackSize; j++) {
- SubsonicFragment frag = (SubsonicFragment)fm.findFragmentByTag(ids[j]);
- fragStack.add(frag);
- }
-
- frags.add(i, fragStack);
- }
- currentPosition = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_POSITION);
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- currentFragment = fragStack.get(fragStack.size() - 1);
- currentFragment.setPrimaryFragment(true);
- activity.invalidateOptionsMenu();
- }
-
- private class TabInfo {
- public final Class fragmentClass;
- public final Bundle args;
- public TabInfo(Class fragmentClass, Bundle args) {
- this.fragmentClass = fragmentClass;
- this.args = args;
- }
- }
- private class QueuedFragment {
- public SubsonicFragment fragment;
- public int id;
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java deleted file mode 100644 index 5cda9ee5..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.activity; - -import android.app.Activity; -import android.app.SearchManager; -import android.content.Intent; -import android.os.Bundle; -import android.provider.SearchRecentSuggestions; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.provider.DSubSearchProvider; - -/** - * 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, DSubSearchProvider.AUTHORITY, - DSubSearchProvider.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/github/daneren2005/dsub/audiofx/EqualizerController.java b/subsonic-android/src/github/daneren2005/dsub/audiofx/EqualizerController.java deleted file mode 100644 index 0dcee863..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/audiofx/EqualizerController.java +++ /dev/null @@ -1,151 +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 github.daneren2005.dsub.audiofx; - -import java.io.Serializable; - -import android.content.Context; -import android.media.MediaPlayer; -import android.media.audiofx.Equalizer; -import android.util.Log; -import github.daneren2005.dsub.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; - private boolean released = false; - private int audioSessionId = 0; - - // 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 { - audioSessionId = mediaPlayer.getAudioSessionId(); - equalizer = new Equalizer(0, audioSessionId); - } 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()) { - released = true; - equalizer.release(); - } - } - - public Equalizer getEqualizer() { - if(released) { - released = false; - try { - equalizer = new Equalizer(0, audioSessionId); - } catch (Throwable x) { - equalizer = null; - Log.w(TAG, "Failed to create equalizer.", x); - } - } - 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/github/daneren2005/dsub/audiofx/VisualizerController.java b/subsonic-android/src/github/daneren2005/dsub/audiofx/VisualizerController.java deleted file mode 100644 index b32245f4..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/audiofx/VisualizerController.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 2011 (C) Sindre Mehus - */ -package github.daneren2005.dsub.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; - private boolean released = false; - private int audioSessionId = 0; - - // Class initialization fails when this throws an exception. - static { - try { - Class.forName("android.media.audiofx.Visualizer"); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - /** - * 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 { - audioSessionId = mediaPlayer.getAudioSessionId(); - visualizer = new Visualizer(audioSessionId); - } catch (Throwable x) { - Log.w(TAG, "Failed to create visualizer.", x); - } - - if (visualizer != null) { - int[] captureSizeRange = Visualizer.getCaptureSizeRange(); - int captureSize = Math.max(PREFERRED_CAPTURE_SIZE, captureSizeRange[0]); - captureSize = Math.min(captureSize, captureSizeRange[1]); - visualizer.setCaptureSize(captureSize); - } - } - - public boolean isAvailable() { - return visualizer != null; - } - - public boolean isEnabled() { - return isAvailable() && visualizer.getEnabled(); - } - - public void release() { - if (isAvailable()) { - visualizer.release(); - released = true; - } - } - - public Visualizer getVisualizer() { - if(released) { - released = false; - try { - visualizer = new Visualizer(audioSessionId); - } catch (Throwable x) { - visualizer = null; - Log.w(TAG, "Failed to create visualizer.", x); - } - } - - return visualizer; - } -} - diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/Artist.java b/subsonic-android/src/github/daneren2005/dsub/domain/Artist.java deleted file mode 100644 index e4a9001b..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/Artist.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 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import java.io.Serializable; - -/** - * @author Sindre Mehus - */ -public class Artist implements Serializable { - - private String id; - private String name; - private String index; - private boolean starred; - private int closeness; - - 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; - } - - public boolean isStarred() { - return starred; - } - - public void setStarred(boolean starred) { - this.starred = starred; - } - - public int getCloseness() { - return closeness; - } - - public void setCloseness(int closeness) { - this.closeness = closeness; - } - - @Override - public String toString() { - return name; - } -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/ChatMessage.java b/subsonic-android/src/github/daneren2005/dsub/domain/ChatMessage.java deleted file mode 100644 index 471594e9..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/ChatMessage.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 github.daneren2005.dsub.domain;
-
-import java.io.Serializable;
-
-public class ChatMessage implements Serializable {
- private String username;
- private Long time;
- private String message;
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public Long getTime() {
- return time;
- }
-
- public void setTime(Long time) {
- this.time = time;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/Genre.java b/subsonic-android/src/github/daneren2005/dsub/domain/Genre.java deleted file mode 100644 index 8c705e31..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/Genre.java +++ /dev/null @@ -1,29 +0,0 @@ -package github.daneren2005.dsub.domain;
-
-import java.io.Serializable;
-
-public class Genre implements Serializable {
- private String name;
- private String index;
-
- 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;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/Indexes.java b/subsonic-android/src/github/daneren2005/dsub/domain/Indexes.java deleted file mode 100644 index 0bc44158..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/domain/JukeboxStatus.java b/subsonic-android/src/github/daneren2005/dsub/domain/JukeboxStatus.java deleted file mode 100644 index 7b229f49..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/domain/Lyrics.java b/subsonic-android/src/github/daneren2005/dsub/domain/Lyrics.java deleted file mode 100644 index feb75cd6..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/domain/MusicDirectory.java b/subsonic-android/src/github/daneren2005/dsub/domain/MusicDirectory.java deleted file mode 100644 index bb49378a..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/MusicDirectory.java +++ /dev/null @@ -1,374 +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 github.daneren2005.dsub.domain; - -import android.util.Log; -import java.util.ArrayList; -import java.util.List; -import java.io.Serializable; -import java.util.Collections; -import java.util.Comparator; - -/** - * @author Sindre Mehus - */ -public class MusicDirectory { - private static final String TAG = MusicDirectory.class.getSimpleName(); - - private String name; - private String id; - private String parent; - private List<Entry> children = new ArrayList<Entry>(); - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - 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 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 int getChildrenSize() { - return children.size(); - } - - public void sortChildren() { - EntryComparator.sort(children); - } - - public static class Entry implements Serializable { - private String id; - private String parent; - private String grandParent; - 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; - private Integer discNumber; - private boolean starred; - private int closeness; - - 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 String getGrandParent() { - return grandParent; - } - - public void setGrandParent(String grandParent) { - this.grandParent = grandParent; - } - - 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; - } - - public Integer getDiscNumber() { - return discNumber; - } - - public void setDiscNumber(Integer discNumber) { - this.discNumber = discNumber; - } - - public boolean isStarred() { - return starred; - } - - public void setStarred(boolean starred) { - this.starred = starred; - } - - public int getCloseness() { - return closeness; - } - - public void setCloseness(int closeness) { - this.closeness = closeness; - } - - @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; - } - } - - public static class EntryComparator implements Comparator<Entry> { - public int compare(Entry lhs, Entry rhs) { - if(lhs.isDirectory() && !rhs.isDirectory()) { - return -1; - } else if(!lhs.isDirectory() && rhs.isDirectory()) { - return 1; - } - - Integer lhsDisc = lhs.getDiscNumber(); - Integer rhsDisc = rhs.getDiscNumber(); - - if(lhsDisc != null && rhsDisc != null) { - if(lhsDisc < rhsDisc) { - return -1; - } else if(lhsDisc > rhsDisc) { - return 1; - } - } else if(lhsDisc != null) { - return -1; - } else if(rhsDisc != null) { - return 1; - } - - Integer lhsTrack = lhs.getTrack(); - Integer rhsTrack = rhs.getTrack(); - if(lhsTrack != null && rhsTrack != null) { - if(lhsTrack < rhsTrack) { - return -1; - } else if(lhsTrack > rhsTrack) { - return 1; - } - } else if(lhsTrack != null) { - return -1; - } else if(rhsTrack != null) { - return 1; - } - - return lhs.getTitle().compareToIgnoreCase(rhs.getTitle()); - } - - public static void sort(List<Entry> entries) { - try { - Collections.sort(entries, new EntryComparator()); - } catch (Exception e) { - Log.w(TAG, "Failed to sort MusicDirectory"); - } - } - } -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/MusicFolder.java b/subsonic-android/src/github/daneren2005/dsub/domain/MusicFolder.java deleted file mode 100644 index 68a22bcc..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/domain/PlayerState.java b/subsonic-android/src/github/daneren2005/dsub/domain/PlayerState.java deleted file mode 100644 index 2b63077b..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/PlayerState.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 github.daneren2005.dsub.domain; - -import android.media.RemoteControlClient; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public enum PlayerState { - IDLE(RemoteControlClient.PLAYSTATE_STOPPED), - DOWNLOADING(RemoteControlClient.PLAYSTATE_BUFFERING), - PREPARING(RemoteControlClient.PLAYSTATE_BUFFERING), - PREPARED(RemoteControlClient.PLAYSTATE_STOPPED), - STARTED(RemoteControlClient.PLAYSTATE_PLAYING), - STOPPED(RemoteControlClient.PLAYSTATE_STOPPED), - PAUSED(RemoteControlClient.PLAYSTATE_PAUSED), - COMPLETED(RemoteControlClient.PLAYSTATE_STOPPED); - - private final int mRemoteControlClientPlayState; - - private PlayerState(int playState) { - mRemoteControlClientPlayState = playState; - } - - public int getRemoteControlClientPlayState() { - return mRemoteControlClientPlayState; - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/Playlist.java b/subsonic-android/src/github/daneren2005/dsub/domain/Playlist.java deleted file mode 100644 index c97659c7..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/Playlist.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 github.daneren2005.dsub.domain; - -import java.io.Serializable; - -/** - * @author Sindre Mehus - */ -public class Playlist implements Serializable { - - private String id; - private String name; - private String owner; - private String comment; - private String songCount; - private String created; - private Boolean pub; - - public Playlist(String id, String name) { - this.id = id; - this.name = name; - } - public Playlist(String id, String name, String owner, String comment, String songCount, String created, String pub) { - this.id = id; - this.name = name; - this.owner = (owner == null) ? "" : owner; - this.comment = (comment == null) ? "" : comment; - this.songCount = (songCount == null) ? "" : songCount; - this.created = (created == null) ? "" : created; - this.pub = (pub == null) ? null : (pub.equals("true")); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getOwner() { - return this.owner; - } - - public void setOwner(String owner) { - this.owner = owner; - } - - public String getComment() { - return this.comment; - } - - public void setComment(String comment) { - this.comment = comment; - } - - public String getSongCount() { - return this.songCount; - } - - public void setSongCount(String songCount) { - this.songCount = songCount; - } - - public String getCreated() { - return this.created; - } - - public void setCreated(String created) { - this.created = created; - } - - public Boolean getPublic() { - return this.pub; - } - public void setPublic(Boolean pub) { - this.pub = pub; - } - - @Override - public String toString() { - return name; - } -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java deleted file mode 100644 index a39e8d04..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java +++ /dev/null @@ -1,80 +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 github.daneren2005.dsub.domain;
-
-import java.io.Serializable;
-
-/**
- *
- * @author Scott
- */
-public class PodcastChannel implements Serializable {
- private String id;
- private String name;
- private String url;
- private String description;
- private String status;
- private String errorMessage;
-
- public PodcastChannel() {
-
- }
-
- 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 getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
-
- public String getDescription() {
- return description;
- }
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getStatus() {
- return status;
- }
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getErrorMessage() {
- return errorMessage;
- }
- public void setErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java deleted file mode 100644 index 01821072..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.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 github.daneren2005.dsub.domain;
-
-/**
- *
- * @author Scott
- */
-public class PodcastEpisode extends MusicDirectory.Entry {
- private String episodeId;
- private String date;
- private String status;
-
- public PodcastEpisode() {
- setDirectory(false);
- }
-
- public String getEpisodeId() {
- return episodeId;
- }
- public void setEpisodeId(String episodeId) {
- this.episodeId = episodeId;
- }
-
- public String getDate() {
- return date;
- }
- public void setDate(String date) {
- this.date = date;
- }
-
- public String getStatus() {
- return status;
- }
- public void setStatus(String status) {
- this.status = status;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/RepeatMode.java b/subsonic-android/src/github/daneren2005/dsub/domain/RepeatMode.java deleted file mode 100644 index 7139029c..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/RepeatMode.java +++ /dev/null @@ -1,28 +0,0 @@ -package github.daneren2005.dsub.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/github/daneren2005/dsub/domain/SearchCritera.java b/subsonic-android/src/github/daneren2005/dsub/domain/SearchCritera.java deleted file mode 100644 index 20d46aa0..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/domain/SearchResult.java b/subsonic-android/src/github/daneren2005/dsub/domain/SearchResult.java deleted file mode 100644 index 11a56540..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/domain/ServerInfo.java b/subsonic-android/src/github/daneren2005/dsub/domain/ServerInfo.java deleted file mode 100644 index 43c7319a..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/domain/Share.java b/subsonic-android/src/github/daneren2005/dsub/domain/Share.java deleted file mode 100644 index d19496f9..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/Share.java +++ /dev/null @@ -1,140 +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 github.daneren2005.dsub.domain;
-
-import github.daneren2005.dsub.domain.MusicDirectory.Entry;
-import java.io.Serializable;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-
-public class Share implements Serializable {
- private String id;
- private String url;
- private String description;
- private String username;
- private Date created;
- private Date lastVisited;
- private Date expires;
- private Long visitCount;
- private List<Entry> entries;
-
- public Share() {
- entries = new ArrayList<Entry>();
- }
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public Date getCreated() {
- return created;
- }
-
- public void setCreated(String created) {
- if (created != null) {
- try {
- this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created);
- } catch (ParseException e) {
- this.created = null;
- }
- } else {
- this.created = null;
- }
- }
-
- public Date getLastVisited() {
- return lastVisited;
- }
-
- public void setLastVisited(String lastVisited) {
- if (lastVisited != null) {
- try {
- this.lastVisited = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(lastVisited);
- } catch (ParseException e) {
- this.lastVisited = null;
- }
- } else {
- this.lastVisited = null;
- }
- }
-
- public Date getExpires() {
- return expires;
- }
-
- public void setExpires(String expires) {
- if (expires != null) {
- try {
- this.expires = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(expires);
- } catch (ParseException e) {
- this.expires = null;
- }
- } else {
- this.expires = null;
- }
- }
-
- public Long getVisitCount() {
- return visitCount;
- }
-
- public void setVisitCount(Long visitCount) {
- this.visitCount = visitCount;
- }
-
- public List<Entry> getEntries() {
- return this.entries;
- }
-
- public void addEntry(Entry entry) {
- entries.add(entry);
- }
- }
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/Version.java b/subsonic-android/src/github/daneren2005/dsub/domain/Version.java deleted file mode 100644 index 40edf563..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/domain/Version.java +++ /dev/null @@ -1,171 +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 github.daneren2005.dsub.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; - } - - public String getVersion() { - switch(major) { - case 1: - switch(minor) { - case 0: - return "3.8"; - case 1: - return "3.9"; - case 2: - return "4.0"; - case 3: - return "4.1"; - case 4: - return "4.2"; - case 5: - return "4.3.1"; - case 6: - return "4.5"; - case 7: - return "4.6"; - case 8: - return "4.7"; - case 9: - return "4.8"; - } - } - return ""; - } - - /** - * 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/github/daneren2005/dsub/fragments/ChatFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/ChatFragment.java deleted file mode 100644 index 4f373442..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/ChatFragment.java +++ /dev/null @@ -1,223 +0,0 @@ -package github.daneren2005.dsub.fragments;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import android.os.Bundle;
-import android.os.Handler;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ListView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.ChatMessage;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.util.BackgroundTask;
-import github.daneren2005.dsub.util.TabBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.ChatAdapter;
-import com.actionbarsherlock.view.Menu;
-import github.daneren2005.dsub.util.Constants;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author Joshua Bahnsen
- */
-public class ChatFragment extends SubsonicFragment {
- private static final String TAG = ChatFragment.class.getSimpleName();
- private ListView chatListView;
- private EditText messageEditText;
- private ImageButton sendButton;
- private Long lastChatMessageTime = (long) 0;
- private ArrayList<ChatMessage> messageList = new ArrayList<ChatMessage>();
- private ScheduledExecutorService executorService;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.chat, container, false);
-
- messageEditText = (EditText) rootView.findViewById(R.id.chat_edittext);
- sendButton = (ImageButton) rootView.findViewById(R.id.chat_send);
-
- sendButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- sendMessage();
- }
- });
-
- chatListView = (ListView) rootView.findViewById(R.id.chat_entries);
-
- messageEditText.setImeActionLabel("Send", KeyEvent.KEYCODE_ENTER);
- messageEditText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
- }
-
- @Override
- public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
- sendButton.setEnabled(!Util.isNullOrWhiteSpace(editable.toString()));
- }
- });
-
- messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_DONE || (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN)) {
- sendMessage();
- return true;
- }
-
- return false;
- }
- });
-
- invalidated = true;
- return rootView;
- }
-
- @Override
- public 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() {
- if(primaryFragment) {
- load(false);
- } else {
- invalidated = true;
- }
- }
- });
- }
- };
-
- SharedPreferences prefs = Util.getPreferences(context);
- long refreshRate = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_CHAT_REFRESH, "30"));
- if(refreshRate > 0) {
- executorService = Executors.newSingleThreadScheduledExecutor();
- executorService.scheduleWithFixedDelay(runnable, refreshRate * 1000L, refreshRate * 1000L, TimeUnit.MILLISECONDS);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- if(executorService != null) {
- executorService.shutdown();
- executorService = null;
- }
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.chat, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- if(super.onOptionsItemSelected(item)) {
- return true;
- }
-
- return false;
- }
-
- @Override
- protected void refresh(boolean refresh) {
- load(refresh);
- }
-
- private synchronized void load(final boolean refresh) {
- Log.i(TAG, "Loading: " + refresh);
- setTitle(R.string.button_bar_chat);
- BackgroundTask<List<ChatMessage>> task = new TabBackgroundTask<List<ChatMessage>>(this) {
- @Override
- protected List<ChatMessage> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- return musicService.getChatMessages(refresh ? 0L : lastChatMessageTime, context, this);
- }
-
- @Override
- protected void done(List<ChatMessage> result) {
- if (result != null && !result.isEmpty()) {
- if(refresh) {
- messageList.clear();
- }
-
- // Reset lastChatMessageTime if we have a newer message
- for (ChatMessage message : result) {
- if (message.getTime() > lastChatMessageTime) {
- lastChatMessageTime = message.getTime();
- }
- }
-
- // Reverse results to show them on the bottom
- Collections.reverse(result);
- messageList.addAll(result);
-
- ChatAdapter chatAdapter = new ChatAdapter(context, messageList);
- chatListView.setAdapter(chatAdapter);
- }
- }
- };
-
- task.execute();
- }
-
- private void sendMessage() {
- final String message = messageEditText.getText().toString();
-
- if (!Util.isNullOrWhiteSpace(message)) {
- messageEditText.setText("");
- InputMethodManager mgr = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
- mgr.hideSoftInputFromWindow(messageEditText.getWindowToken(), 0);
-
- BackgroundTask<Void> task = new TabBackgroundTask<Void>(this) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.addChatMessage(message, context, this);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- load(false);
- }
- };
-
- task.execute();
- }
- }
-}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java deleted file mode 100644 index 56accc30..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java +++ /dev/null @@ -1,1169 +0,0 @@ -package github.daneren2005.dsub.fragments;
-
-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.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.Color;
-import android.graphics.Typeface;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.Display;
-import android.view.GestureDetector;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-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.SeekBar;
-import android.widget.TextView;
-import android.widget.ViewFlipper;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuItem;
-import com.actionbarsherlock.view.MenuInflater;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.PlayerState;
-import github.daneren2005.dsub.domain.RepeatMode;
-import github.daneren2005.dsub.service.DownloadFile;
-import github.daneren2005.dsub.service.DownloadService;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.SilentBackgroundTask;
-import github.daneren2005.dsub.view.FadeOutAnimation;
-import github.daneren2005.dsub.view.SongView;
-import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.VisualizerView;
-
-import static github.daneren2005.dsub.domain.PlayerState.*;
-import github.daneren2005.dsub.util.*;
-import github.daneren2005.dsub.view.AutoRepeatButton;
-import java.util.ArrayList;
-import java.util.concurrent.ScheduledFuture;
-import com.mobeta.android.dslv.*;
-import github.daneren2005.dsub.activity.EqualizerActivity;
-import github.daneren2005.dsub.activity.MainActivity;
-import github.daneren2005.dsub.activity.SubsonicActivity;
-
-public class DownloadFragment extends SubsonicFragment implements OnGestureListener {
- private static final String TAG = DownloadFragment.class.getSimpleName();
-
- public static final int DIALOG_SAVE_PLAYLIST = 100;
- private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 10;
- private static final int COLOR_BUTTON_ENABLED = Color.rgb(51, 181, 229);
- private static final int COLOR_BUTTON_DISABLED = Color.rgb(206, 213, 211);
- private static final int INCREMENT_TIME = 5000;
-
- private ViewFlipper playlistFlipper;
- private TextView emptyTextView;
- private TextView songTitleTextView;
- private ImageView albumArtImageView;
- private DragSortListView playlistView;
- private TextView positionTextView;
- private TextView durationTextView;
- private TextView statusTextView;
- private SeekBar progressBar;
- private AutoRepeatButton previousButton;
- private AutoRepeatButton nextButton;
- private View pauseButton;
- private View stopButton;
- private View startButton;
- private ImageButton repeatButton;
- private Button equalizerButton;
- private Button visualizerButton;
- private Button jukeboxButton;
- private View toggleListButton;
- private ImageButton starButton;
- private View mainLayout;
- private ScheduledExecutorService executorService;
- private DownloadFile currentPlaying;
- private long currentRevision;
- private GestureDetector gestureScanner;
- private int swipeDistance;
- private int swipeVelocity;
- private VisualizerView visualizerView;
- private boolean nowPlaying = true;
- private ScheduledFuture<?> hideControlsFuture;
- private SongListAdapter songListAdapter;
- private SilentBackgroundTask<Void> onProgressChangedTask;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.download, container, false);
- setTitle(nowPlaying ? "Now Playing" : "Downloading");
-
- mainLayout = rootView.findViewById(R.id.download_layout);
- if(!primaryFragment) {
- mainLayout.setVisibility(View.GONE);
- }
-
- WindowManager w = context.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)rootView.findViewById(R.id.download_playlist_flipper);
- emptyTextView = (TextView)rootView.findViewById(R.id.download_empty);
- songTitleTextView = (TextView)rootView.findViewById(R.id.download_song_title);
- albumArtImageView = (ImageView)rootView.findViewById(R.id.download_album_art_image);
- positionTextView = (TextView)rootView.findViewById(R.id.download_position);
- durationTextView = (TextView)rootView.findViewById(R.id.download_duration);
- statusTextView = (TextView)rootView.findViewById(R.id.download_status);
- progressBar = (SeekBar)rootView.findViewById(R.id.download_progress_bar);
- playlistView = (DragSortListView)rootView.findViewById(R.id.download_list);
- previousButton = (AutoRepeatButton)rootView.findViewById(R.id.download_previous);
- nextButton = (AutoRepeatButton)rootView.findViewById(R.id.download_next);
- pauseButton =rootView.findViewById(R.id.download_pause);
- stopButton =rootView.findViewById(R.id.download_stop);
- startButton =rootView.findViewById(R.id.download_start);
- repeatButton = (ImageButton)rootView.findViewById(R.id.download_repeat);
- equalizerButton = (Button)rootView.findViewById(R.id.download_equalizer);
- visualizerButton = (Button)rootView.findViewById(R.id.download_visualizer);
- jukeboxButton = (Button)rootView.findViewById(R.id.download_jukebox);
- LinearLayout visualizerViewLayout = (LinearLayout)rootView.findViewById(R.id.download_visualizer_view_layout);
- toggleListButton =rootView.findViewById(R.id.download_toggle_list);
-
- starButton = (ImageButton)rootView.findViewById(R.id.download_star);
- starButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- DownloadFile currentDownload = getDownloadService().getCurrentPlaying();
- if (currentDownload != null) {
- MusicDirectory.Entry currentSong = currentDownload.getSong();
- toggleStarred(currentSong);
- starButton.setImageResource(currentSong.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
- }
- }
- });
-
- View.OnTouchListener touchListener = new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent me) {
- return gestureScanner.onTouchEvent(me);
- }
- };
- pauseButton.setOnTouchListener(touchListener);
- stopButton.setOnTouchListener(touchListener);
- startButton.setOnTouchListener(touchListener);
- equalizerButton.setOnTouchListener(touchListener);
- visualizerButton.setOnTouchListener(touchListener);
- jukeboxButton.setOnTouchListener(touchListener);
- emptyTextView.setOnTouchListener(touchListener);
- albumArtImageView.setOnTouchListener(touchListener);
-
- previousButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().previous();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- setControlsVisible(true);
- }
- });
- previousButton.setOnRepeatListener(new Runnable() {
- public void run() {
- changeProgress(-INCREMENT_TIME);
- }
- });
-
- nextButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- new SilentBackgroundTask<Boolean>(context) {
- @Override
- protected Boolean doInBackground() throws Throwable {
- if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) {
- getDownloadService().next();
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- protected void done(Boolean result) {
- if(result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }
- }.execute();
- setControlsVisible(true);
- }
- });
- nextButton.setOnRepeatListener(new Runnable() {
- public void run() {
- changeProgress(INCREMENT_TIME);
- }
- });
-
- pauseButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().pause();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- }
- });
-
- stopButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().reset();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- }
- });
-
- startButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- start();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- }
- });
-
- 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(context, R.string.download_repeat_off);
- break;
- case ALL:
- Util.toast(context, R.string.download_repeat_all);
- break;
- case SINGLE:
- Util.toast(context, R.string.download_repeat_single);
- break;
- default:
- break;
- }
- setControlsVisible(true);
- }
- });
-
- equalizerButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- DownloadService downloadService = getDownloadService();
- if(downloadService != null && downloadService.getEqualizerController() != null
- && downloadService.getEqualizerController().getEqualizer() != null) {
- context.startActivity(new Intent(context, EqualizerActivity.class));
- setControlsVisible(true);
- } else {
- Util.toast(context, "Failed to start equalizer. Try restarting.");
- }
- }
- });
-
- visualizerButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- boolean active = !visualizerView.isActive();
- visualizerView.setActive(active);
- boolean isActive = visualizerView.isActive();
- getDownloadService().setShowVisualization(isActive);
- updateButtons();
- if(active == isActive) {
- Util.toast(context, active ? R.string.download_visualizer_on : R.string.download_visualizer_off);
- } else {
- Util.toast(context, "Failed to start visualizer. Try restarting.");
- }
- setControlsVisible(true);
- }
- });
-
- jukeboxButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- boolean jukeboxEnabled = !getDownloadService().isJukeboxEnabled();
- getDownloadService().setJukeboxEnabled(jukeboxEnabled);
- updateButtons();
- Util.toast(context, jukeboxEnabled ? R.string.download_jukebox_on : R.string.download_jukebox_off, false);
- setControlsVisible(true);
- }
- });
-
- toggleListButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- toggleFullscreenAlbumArt();
- setControlsVisible(true);
- }
- });
-
- progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onStopTrackingTouch(final SeekBar seekBar) {
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().seekTo(progressBar.getProgress());
- return null;
- }
-
- @Override
- protected void done(Void result) {
- DownloadFragment.this.onProgressChanged();
- }
- }.execute();
- }
-
- @Override
- public void onStartTrackingTouch(final SeekBar seekBar) {
-
- }
-
- @Override
- public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) {
-
- }
- });
- playlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
- if(nowPlaying) {
- warnIfNetworkOrStorageUnavailable();
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().play(position);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- }
- }
- });
- playlistView.setDropListener(new DragSortListView.DropListener() {
- @Override
- public void drop(int from, int to) {
- getDownloadService().swap(nowPlaying, from, to);
- onDownloadListChanged();
- }
- });
- playlistView.setRemoveListener(new DragSortListView.RemoveListener() {
- @Override
- public void remove(int which) {
- getDownloadService().remove(which);
- onDownloadListChanged();
- }
- });
-
- registerForContextMenu(playlistView);
-
- DownloadService downloadService = getDownloadService();
- if (downloadService != null && context.getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) {
- context.getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE);
- warnIfNetworkOrStorageUnavailable();
- downloadService.setShufflePlayEnabled(true);
- }
-
- boolean visualizerAvailable = downloadService != null && downloadService.getVisualizerAvailable();
- boolean equalizerAvailable = downloadService != null && downloadService.getEqualizerAvailable();
-
- if (!equalizerAvailable) {
- equalizerButton.setVisibility(View.GONE);
- }
- if (!visualizerAvailable) {
- visualizerButton.setVisibility(View.GONE);
- } else {
- visualizerView = new VisualizerView(context);
- visualizerViewLayout.addView(visualizerView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
- }
-
- // TODO: Extract to utility method and cache.
- Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Storopia.ttf");
- equalizerButton.setTypeface(typeface);
- visualizerButton.setTypeface(typeface);
- jukeboxButton.setTypeface(typeface);
-
- return rootView;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
- if(Util.isOffline(context)) {
- menuInflater.inflate(R.menu.nowplaying_offline, menu);
- } else {
- if(nowPlaying) {
- menuInflater.inflate(R.menu.nowplaying, menu);
- }
- else {
- menuInflater.inflate(R.menu.nowplaying_downloading, menu);
- }
-
- if(getDownloadService() != null && getDownloadService().getSleepTimer()) {
- menu.findItem(R.id.menu_toggle_timer).setTitle(R.string.download_stop_timer);
- }
- }
- if(getDownloadService() != null && getDownloadService().getKeepScreenOn()) {
- menu.findItem(R.id.menu_screen_on_off).setTitle(R.string.download_menu_screen_off);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- if(menuItemSelected(menuItem.getItemId(), null)) {
- return true;
- }
-
- return super.onOptionsItemSelected(menuItem);
- }
-
- @Override
- public void onCreateContextMenu(android.view.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);
-
- android.view.MenuInflater inflater = context.getMenuInflater();
- if(Util.isOffline(context)) {
- inflater.inflate(R.menu.nowplaying_context_offline, menu);
- } else {
- inflater.inflate(R.menu.nowplaying_context, menu);
- menu.findItem(R.id.menu_star).setTitle(downloadFile.getSong().isStarred() ? R.string.common_unstar : R.string.common_star);
- }
-
- if (downloadFile.getSong().getParent() == null) {
- menu.findItem(R.id.menu_show_album).setVisible(false);
- }
- }
- }
-
- @Override
- public boolean onContextItemSelected(android.view.MenuItem menuItem) {
- if(!primaryFragment) {
- return false;
- }
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position);
- return menuItemSelected(menuItem.getItemId(), downloadFile) || super.onContextItemSelected(menuItem);
- }
-
- private boolean menuItemSelected(int menuItemId, final DownloadFile song) {
- switch (menuItemId) {
- case R.id.menu_show_album:
- MusicDirectory.Entry entry = song.getSong();
-
- Intent intent = new Intent(context, MainActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_VIEW_ALBUM, true);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, entry.getParent());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, entry.getAlbum());
-
- if(entry.getGrandParent() != null) {
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.getGrandParent());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_NAME, entry.getArtist());
- }
-
- if(Util.isOffline(context)) {
- try {
- // This should only be succesful if this is a online song in offline mode
- Integer.parseInt(entry.getParent());
- String root = FileUtil.getMusicDirectory(context).getPath();
- String id = root + "/" + entry.getPath();
- id = id.substring(0, id.lastIndexOf("/"));
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, id);
- id = id.substring(0, id.lastIndexOf("/"));
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID, id);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_NAME, entry.getArtist());
- } catch(Exception e) {
- // Do nothing, entry.getParent() is fine
- }
- }
-
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Util.startActivityWithoutTransition(context, intent);
- return true;
- case R.id.menu_lyrics:
- SubsonicFragment fragment = new LyricsFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ARTIST, song.getSong().getArtist());
- args.putString(Constants.INTENT_EXTRA_NAME_TITLE, song.getSong().getTitle());
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.download_layout_container);
- return true;
- case R.id.menu_remove:
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().remove(song);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onDownloadListChanged();
- }
- }.execute();
- return true;
- case R.id.menu_delete:
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(1);
- songs.add(song.getSong());
- getDownloadService().delete(songs);
- return true;
- case R.id.menu_remove_all:
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().setShufflePlayEnabled(false);
- if(nowPlaying) {
- getDownloadService().clear();
- }
- else {
- getDownloadService().clearBackground();
- }
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onDownloadListChanged();
- }
- }.execute();
- return true;
- case R.id.menu_screen_on_off:
- if (getDownloadService().getKeepScreenOn()) {
- context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- getDownloadService().setKeepScreenOn(false);
- } else {
- context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- getDownloadService().setKeepScreenOn(true);
- }
- context.invalidateOptionsMenu();
- return true;
- case R.id.menu_shuffle:
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().shuffle();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(context, R.string.download_menu_shuffle_notification);
- }
- }.execute();
- return true;
- case R.id.menu_save_playlist:
- List<MusicDirectory.Entry> entries = new LinkedList<MusicDirectory.Entry>();
- for (DownloadFile downloadFile : getDownloadService().getSongs()) {
- entries.add(downloadFile.getSong());
- }
- createNewPlaylist(entries, true);
- return true;
- case R.id.menu_star:
- toggleStarred(song.getSong());
- return true;
- case R.id.menu_toggle_now_playing:
- toggleNowPlaying();
- context.invalidateOptionsMenu();
- return true;
- case R.id.menu_toggle_timer:
- if(getDownloadService().getSleepTimer()) {
- getDownloadService().stopSleepTimer();
- context.invalidateOptionsMenu();
- } else {
- startTimer();
- }
- return true;
- case R.id.menu_add_playlist:
- songs = new ArrayList<MusicDirectory.Entry>(1);
- songs.add(song.getSong());
- addToPlaylist(songs);
- return true;
- case R.id.menu_info:
- displaySongInfo(song.getSong());
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public 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);
-
- setControlsVisible(true);
-
- DownloadService downloadService = getDownloadService();
- if (downloadService == null || downloadService.getCurrentPlaying() == null) {
- playlistFlipper.setDisplayedChild(1);
- }
-
- scrollToCurrent();
- if (downloadService != null && downloadService.getKeepScreenOn()) {
- context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- } else {
- context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- if (visualizerView != null && downloadService != null && downloadService.getShowVisualization()) {
- visualizerView.setActive(true);
- }
-
- updateButtons();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- executorService.shutdown();
- if (visualizerView != null && visualizerView.isActive()) {
- visualizerView.setActive(false);
- }
- }
-
- @Override
- public void setPrimaryFragment(boolean primary) {
- super.setPrimaryFragment(primary);
- if(rootView != null) {
- if(primary) {
- mainLayout.setVisibility(View.VISIBLE);
- } else {
- mainLayout.setVisibility(View.GONE);
- }
- }
- }
-
- private void scheduleHideControls() {
- if (hideControlsFuture != null) {
- hideControlsFuture.cancel(false);
- }
-
- final Handler handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- handler.post(new Runnable() {
- @Override
- public void run() {
- setControlsVisible(false);
- }
- });
- }
- };
- hideControlsFuture = executorService.schedule(runnable, 3000L, TimeUnit.MILLISECONDS);
- }
-
- private void setControlsVisible(boolean visible) {
- try {
- long duration = 1700L;
- FadeOutAnimation.createAndStart(rootView.findViewById(R.id.download_overlay_buttons), !visible, duration);
-
- if (visible) {
- scheduleHideControls();
- }
- } catch(Exception e) {
-
- }
- }
-
- private void updateButtons() {
- SharedPreferences prefs = Util.getPreferences(context);
- boolean equalizerOn = prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false);
- if(equalizerOn && getDownloadService() != null && getDownloadService().getEqualizerController() != null &&
- getDownloadService().getEqualizerController().isEnabled()) {
- equalizerButton.setTextColor(COLOR_BUTTON_ENABLED);
- } else {
- equalizerButton.setTextColor(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 || songListAdapter == null) {
- return;
- }
-
- for (int i = 0; i < songListAdapter.getCount(); i++) {
- if (currentPlaying == playlistView.getItemAtPosition(i)) {
- playlistView.setSelectionFromTop(i, 40);
- return;
- }
- }
- DownloadFile currentDownloading = getDownloadService().getCurrentDownloading();
- for (int i = 0; i < songListAdapter.getCount(); i++) {
- if (currentDownloading == playlistView.getItemAtPosition(i)) {
- playlistView.setSelectionFromTop(i, 40);
- return;
- }
- }
- }
-
- private void update() {
- if (getDownloadService() == null) {
- return;
- }
-
- if (currentRevision != getDownloadService().getDownloadListUpdateRevision()) {
- onDownloadListChanged();
- }
-
- if (currentPlaying != getDownloadService().getCurrentPlaying()) {
- onCurrentChanged();
- }
-
- onProgressChanged();
- }
-
- protected void startTimer() {
- View dialogView = context.getLayoutInflater().inflate(R.layout.start_timer, null);
- final EditText lengthBox = (EditText)dialogView.findViewById(R.id.timer_length);
-
- final SharedPreferences prefs = Util.getPreferences(context);
- lengthBox.setText(prefs.getString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, ""));
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.menu_set_timer)
- .setView(dialogView)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- String length = lengthBox.getText().toString();
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, length);
- editor.commit();
-
- getDownloadService().setSleepTimerDuration(Integer.parseInt(length));
- getDownloadService().startSleepTimer();
- context.invalidateOptionsMenu();
- }
- })
- .setNegativeButton(R.string.common_cancel, null);
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- private void toggleFullscreenAlbumArt() {
- if (playlistFlipper.getDisplayedChild() == 1) {
- playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_in));
- playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_out));
- playlistFlipper.setDisplayedChild(0);
- } else {
- scrollToCurrent();
- playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_in));
- playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_out));
- playlistFlipper.setDisplayedChild(1);
- }
- }
-
- private void start() {
- DownloadService service = getDownloadService();
- PlayerState state = service.getPlayerState();
- if (state == PAUSED || state == COMPLETED || state == STOPPED) {
- 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() {
- onDownloadListChanged(false);
- }
- private void onDownloadListChanged(boolean refresh) {
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
- return;
- }
-
- List<DownloadFile> list;
- if(nowPlaying) {
- list = downloadService.getSongs();
- }
- else {
- list = downloadService.getBackgroundDownloads();
- }
-
- if(downloadService.isShufflePlayEnabled()) {
- emptyTextView.setText(R.string.download_shuffle_loading);
- }
- else {
- emptyTextView.setText(R.string.download_empty);
- }
-
- if(songListAdapter == null || refresh) {
- playlistView.setAdapter(songListAdapter = new SongListAdapter(list));
- } else {
- songListAdapter.notifyDataSetChanged();
- }
- emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE);
- currentRevision = downloadService.getDownloadListUpdateRevision();
-
- switch (downloadService.getRepeatMode()) {
- case OFF:
- if("light".equals(SubsonicActivity.getThemeName()) | "light_fullscreen".equals(SubsonicActivity.getThemeName())) {
- repeatButton.setImageResource(R.drawable.media_repeat_off_light);
- } else {
- 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;
- }
-
- setSubtitle(context.getResources().getString(R.string.download_playing_out_of, downloadService.getCurrentPlayingIndex() + 1, downloadService.size()));
- }
-
- private void onCurrentChanged() {
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
- return;
- }
-
- currentPlaying = downloadService.getCurrentPlaying();
- if (currentPlaying != null) {
- MusicDirectory.Entry song = currentPlaying.getSong();
- songTitleTextView.setText(song.getTitle());
- getImageLoader().loadImage(albumArtImageView, song, true, true);
- starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
- setSubtitle(context.getResources().getString(R.string.download_playing_out_of, downloadService.getCurrentPlayingIndex() + 1, downloadService.size()));
- } else {
- songTitleTextView.setText(null);
- getImageLoader().loadImage(albumArtImageView, null, true, false);
- starButton.setImageResource(android.R.drawable.btn_star_big_off);
- setSubtitle(null);
- }
- }
-
- private void onProgressChanged() {
- // Make sure to only be trying to run one of these at a time
- if (getDownloadService() == null || onProgressChangedTask != null) {
- return;
- }
-
- onProgressChangedTask = new SilentBackgroundTask<Void>(context) {
- DownloadService downloadService;
- boolean isJukeboxEnabled;
- int millisPlayed;
- Integer duration;
- PlayerState playerState;
-
- @Override
- protected Void doInBackground() throws Throwable {
- downloadService = getDownloadService();
- isJukeboxEnabled = downloadService.isJukeboxEnabled();
- millisPlayed = Math.max(0, downloadService.getPlayerPosition());
- duration = downloadService.getPlayerDuration();
- playerState = getDownloadService().getPlayerState();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- if (currentPlaying != null) {
- 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.setEnabled(currentPlaying.isWorkDone() || isJukeboxEnabled);
- } else {
- positionTextView.setText("0:00");
- durationTextView.setText("-:--");
- progressBar.setProgress(0);
- progressBar.setEnabled(false);
- }
-
- switch (playerState) {
- case DOWNLOADING:
- long bytes = currentPlaying.getPartialFile().length();
- statusTextView.setText(context.getResources().getString(R.string.download_playerstate_downloading, Util.formatLocalizedBytes(bytes, context)));
- break;
- case PREPARING:
- statusTextView.setText(R.string.download_playerstate_buffering);
- break;
- default:
- if(currentPlaying != null) {
- String artist = "";
- if(currentPlaying.getSong().getArtist() != null) {
- artist = currentPlaying.getSong().getArtist() + " - ";
- }
- statusTextView.setText(artist + currentPlaying.getSong().getAlbum());
- } else {
- statusTextView.setText(null);
- }
- break;
- }
-
- switch (playerState) {
- case STARTED:
- pauseButton.setVisibility(View.VISIBLE);
- stopButton.setVisibility(View.INVISIBLE);
- startButton.setVisibility(View.INVISIBLE);
- break;
- case DOWNLOADING:
- case PREPARING:
- pauseButton.setVisibility(View.INVISIBLE);
- stopButton.setVisibility(View.VISIBLE);
- startButton.setVisibility(View.INVISIBLE);
- break;
- default:
- pauseButton.setVisibility(View.INVISIBLE);
- stopButton.setVisibility(View.INVISIBLE);
- startButton.setVisibility(View.VISIBLE);
- break;
- }
-
- jukeboxButton.setTextColor(isJukeboxEnabled ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
- onProgressChangedTask = null;
- }
- };
- onProgressChangedTask.execute();
- }
-
- private void changeProgress(final int ms) {
- final DownloadService downloadService = getDownloadService();
- if(downloadService == null) {
- return;
- }
-
- new SilentBackgroundTask<Void>(context) {
- boolean isJukeboxEnabled;
- int msPlayed;
- Integer duration;
- PlayerState playerState;
- int seekTo;
-
- @Override
- protected Void doInBackground() throws Throwable {
- msPlayed = Math.max(0, downloadService.getPlayerPosition());
- duration = downloadService.getPlayerDuration();
- playerState = getDownloadService().getPlayerState();
- int msTotal = duration == null ? 0 : duration;
- if(msPlayed + ms > msTotal) {
- seekTo = msTotal;
- } else {
- seekTo = msPlayed + ms;
- }
- downloadService.seekTo(seekTo);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- progressBar.setProgress(seekTo);
- }
- }.execute();
- }
-
- private class SongListAdapter extends ArrayAdapter<DownloadFile> {
- public SongListAdapter(List<DownloadFile> entries) {
- super(context, 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(context);
- }
- DownloadFile downloadFile = getItem(position);
- view.setSong(downloadFile.getSong(), false);
- return view;
- }
- }
-
- @Override
- public boolean onDown(MotionEvent me) {
- setControlsVisible(true);
- return false;
- }
-
- public GestureDetector getGestureDetector() {
- return gestureScanner;
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
- return false;
- }
- Log.d(TAG, "onFling");
-
- // 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
- else if (e2.getX() - e1.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.previous();
- onCurrentChanged();
- onProgressChanged();
- return true;
- }
-
- // Top to Bottom swipe
- else if (e2.getY() - e1.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.seekTo(downloadService.getPlayerPosition() + 30000);
- onProgressChanged();
- return true;
- }
-
- // Bottom to Top swipe
- else if (e1.getY() - e2.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.seekTo(downloadService.getPlayerPosition() - 8000);
- onProgressChanged();
- return true;
- }
-
- return false;
- }
-
- private void toggleNowPlaying() {
- nowPlaying = !nowPlaying;
- setTitle(nowPlaying ? "Now Playing" : "Downloading");
- onDownloadListChanged(true);
- }
-
- @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/github/daneren2005/dsub/fragments/LyricsFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/LyricsFragment.java deleted file mode 100644 index 0b247986..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/LyricsFragment.java +++ /dev/null @@ -1,81 +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 github.daneren2005.dsub.fragments; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.TabBackgroundTask; - -/** - * Displays song lyrics. - * - * @author Sindre Mehus - */ -public final class LyricsFragment extends SubsonicFragment { - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - setTitle(R.string.download_menu_lyrics); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.lyrics, container, false); - load(); - - return rootView; - } - - private void load() { - BackgroundTask<Lyrics> task = new TabBackgroundTask<Lyrics>(this) { - @Override - protected Lyrics doInBackground() throws Throwable { - String artist = getArguments().getString(Constants.INTENT_EXTRA_NAME_ARTIST); - String title = getArguments().getString(Constants.INTENT_EXTRA_NAME_TITLE); - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.getLyrics(artist, title, context, this); - } - - @Override - protected void done(Lyrics result) { - TextView artistView = (TextView) rootView.findViewById(R.id.lyrics_artist); - TextView titleView = (TextView) rootView.findViewById(R.id.lyrics_title); - TextView textView = (TextView) rootView.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/github/daneren2005/dsub/fragments/MainFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java deleted file mode 100644 index 9a48acd5..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java +++ /dev/null @@ -1,373 +0,0 @@ -package github.daneren2005.dsub.fragments;
-
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.StatFs;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.CheckBox;
-import android.widget.ListView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.service.DownloadService;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.LoadingTask;
-import github.daneren2005.dsub.view.MergeAdapter;
-import github.daneren2005.dsub.util.Util;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuItem;
-import com.actionbarsherlock.view.MenuInflater;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.util.SilentBackgroundTask;
-import github.daneren2005.dsub.view.ChangeLog;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class MainFragment extends SubsonicFragment {
- private static final String TAG = MainFragment.class.getSimpleName();
- private LayoutInflater inflater;
-
- private static final int MENU_GROUP_SERVER = 10;
- private static final int MENU_ITEM_SERVER_BASE = 100;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- this.inflater = inflater;
- rootView = inflater.inflate(R.layout.home, container, false);
-
- createLayout();
-
- return rootView;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.main, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if(super.onOptionsItemSelected(item)) {
- return true;
- }
-
- switch (item.getItemId()) {
- case R.id.menu_log:
- getLogs();
- return true;
- case R.id.menu_about:
- showAboutDialog();
- return true;
- case R.id.menu_changelog:
- ChangeLog changeLog = new ChangeLog(context, Util.getPreferences(context));
- changeLog.getFullLogDialog().show();
- }
-
- return false;
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- int serverCount = Util.getServerCount(context);
- int activeServer = Util.getActiveServer(context);
- for(int i = 1; i <= serverCount; i++) {
- android.view.MenuItem menuItem = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_BASE + i, MENU_ITEM_SERVER_BASE + i, Util.getServerName(context, i));
- if(i == activeServer) {
- menuItem.setChecked(true);
- }
- }
- menu.setGroupCheckable(MENU_GROUP_SERVER, true, true);
- menu.setHeaderTitle(R.string.main_select_server);
- }
-
- @Override
- public boolean onContextItemSelected(android.view.MenuItem menuItem) {
- if(!primaryFragment) {
- return false;
- }
-
- int activeServer = menuItem.getItemId() - MENU_ITEM_SERVER_BASE;
- setActiveServer(activeServer);
- context.getPagerAdapter().invalidate();
- return true;
- }
-
- @Override
- protected void refresh(boolean refresh) {
- createLayout();
- }
-
- private void createLayout() {
- View buttons = inflater.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 TextView offlineButton = (TextView) buttons.findViewById(R.id.main_offline);
- offlineButton.setText(Util.isOffline(context) ? R.string.main_online : R.string.main_offline);
-
- 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 albumsStarredButton = buttons.findViewById(R.id.main_albums_starred);
- final View albumsGenresButton = buttons.findViewById(R.id.main_albums_genres);
-
- final View dummyView = rootView.findViewById(R.id.main_dummy);
-
- int instance = Util.getActiveServer(context);
- String name = Util.getServerName(context, instance);
- serverTextView.setText(name);
-
- ListView list = (ListView) rootView.findViewById(R.id.main_list);
-
- MergeAdapter adapter = new MergeAdapter();
- if (!Util.isOffline(context)) {
- adapter.addViews(Arrays.asList(serverButton), true);
- }
- adapter.addView(offlineButton, true);
- if (!Util.isOffline(context)) {
- adapter.addView(albumsTitle, false);
- adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton, albumsHighestButton, albumsStarredButton, albumsGenresButton, 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 == offlineButton) {
- toggleOffline();
- } 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");
- } else if (view == albumsStarredButton) {
- showAlbumList("starred");
- } else if(view == albumsGenresButton) {
- showAlbumList("genres");
- }
- }
- });
- }
-
- private void setActiveServer(int instance) {
- if (Util.getActiveServer(context) != instance) {
- DownloadService service = getDownloadService();
- if (service != null) {
- service.clearIncomplete();
- }
- Util.setActiveServer(context, instance);
- }
- }
-
- private void toggleOffline() {
- boolean isOffline = Util.isOffline(context);
- Util.setOffline(context, !isOffline);
- context.getPagerAdapter().invalidate();
-
- if(isOffline) {
- int scrobblesCount = Util.offlineScrobblesCount(context);
- int starsCount = Util.offlineStarsCount(context);
- if(scrobblesCount > 0 || starsCount > 0){
- showOfflineSyncDialog(scrobblesCount, starsCount);
- }
- }
- }
-
- private void showAlbumList(String type) {
- if("genres".equals(type)) {
- SubsonicFragment fragment = new SelectGenreFragment();
- replaceFragment(fragment, R.id.home_layout);
- } else {
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type);
- args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20);
- args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.home_layout);
- }
- }
-
- private void showOfflineSyncDialog(final int scrobbleCount, final int starsCount) {
- String syncDefault = Util.getSyncDefault(context);
- if(syncDefault != null) {
- if("sync".equals(syncDefault)) {
- syncOffline(scrobbleCount, starsCount);
- return;
- } else if("delete".equals(syncDefault)) {
- deleteOffline();
- return;
- }
- }
-
- View checkBoxView = context.getLayoutInflater().inflate(R.layout.sync_dialog, null);
- final CheckBox checkBox = (CheckBox)checkBoxView.findViewById(R.id.sync_default);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setIcon(android.R.drawable.ic_dialog_info)
- .setTitle(R.string.offline_sync_dialog_title)
- .setMessage(context.getResources().getString(R.string.offline_sync_dialog_message, scrobbleCount, starsCount))
- .setView(checkBoxView)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- if(checkBox.isChecked()) {
- Util.setSyncDefault(context, "sync");
- }
- syncOffline(scrobbleCount, starsCount);
- }
- }).setNeutralButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- dialogInterface.dismiss();
- }
- }).setNegativeButton(R.string.common_delete, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- if(checkBox.isChecked()) {
- Util.setSyncDefault(context, "delete");
- }
- deleteOffline();
- }
- });
-
- builder.create().show();
- }
-
- private void syncOffline(final int scrobbleCount, final int starsCount) {
- new SilentBackgroundTask<Integer>(context) {
- @Override
- protected Integer doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- return musicService.processOfflineSyncs(context, null);
- }
-
- @Override
- protected void done(Integer result) {
- if(result == scrobbleCount) {
- Util.toast(context, context.getResources().getString(R.string.offline_sync_success, result));
- } else {
- Util.toast(context, context.getResources().getString(R.string.offline_sync_partial, result, scrobbleCount + starsCount));
- }
- }
-
- @Override
- protected void error(Throwable error) {
- String msg = context.getResources().getString(R.string.offline_sync_error) + " " + getErrorMessage(error);
- Util.toast(context, msg);
- }
- }.execute();
- }
- private void deleteOffline() {
- SharedPreferences.Editor offline = Util.getOfflineSync(context).edit();
- offline.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0);
- offline.commit();
- }
-
- private void showAboutDialog() {
- try {
- File rootFolder = FileUtil.getMusicDirectory(context);
- StatFs stat = new StatFs(rootFolder.getPath());
- long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
- long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
-
- String msg = getResources().getString(R.string.main_about_text,
- context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName,
- Util.formatBytes(FileUtil.getUsedSize(context, rootFolder)),
- Util.formatBytes(Util.getCacheSizeMB(context) * 1024L * 1024L),
- Util.formatBytes(bytesAvailableFs),
- Util.formatBytes(bytesTotalFs));
- Util.info(context, R.string.main_about_title, msg);
- } catch(Exception e) {
- Util.toast(context, "Failed to open dialog");
- }
- }
-
- private void getLogs() {
- try {
- final String version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
- new LoadingTask<File>(context) {
- @Override
- protected File doInBackground() throws Throwable {
- updateProgress("Gathering Logs");
- File logcat = new File(FileUtil.getSubsonicDirectory(), "logcat.txt");
- Process logcatProc = null;
-
- try {
- List<String> progs = new ArrayList<String>();
- progs.add("logcat");
- progs.add("-v");
- progs.add("time");
- progs.add("-d");
- progs.add("-f");
- progs.add(logcat.getPath());
- progs.add("*:I");
-
- logcatProc = Runtime.getRuntime().exec(progs.toArray(new String[0]));
- logcatProc.waitFor();
- } catch(Exception e) {
- Util.toast(context, "Failed to gather logs");
- } finally {
- if(logcatProc != null) {
- logcatProc.destroy();
- }
- }
-
- return logcat;
- }
-
- @Override
- protected void done(File logcat) {
- Intent email = new Intent(android.content.Intent.ACTION_SEND);
- email.setType("text/plain");
- email.putExtra(Intent.EXTRA_EMAIL, new String[] {"dsub.android@gmail.com"});
- email.putExtra(Intent.EXTRA_SUBJECT, "DSub " + version + " Error Logs");
- email.putExtra(Intent.EXTRA_TEXT, "Describe the problem here");
- Uri attachment = Uri.fromFile(logcat);
- email.putExtra(Intent.EXTRA_STREAM, attachment);
- startActivity(email);
- }
- }.execute();
- } catch(Exception e) {}
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java deleted file mode 100644 index 1c35d38c..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java +++ /dev/null @@ -1,333 +0,0 @@ -package github.daneren2005.dsub.fragments;
-
-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.View;
-import android.view.MenuItem;
-import android.widget.AdapterView;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.net.Uri;
-import android.view.ViewGroup;
-import com.actionbarsherlock.view.Menu;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.activity.SearchActivity;
-import github.daneren2005.dsub.domain.Artist;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.SearchCritera;
-import github.daneren2005.dsub.domain.SearchResult;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.service.DownloadService;
-import github.daneren2005.dsub.view.ArtistAdapter;
-import github.daneren2005.dsub.util.BackgroundTask;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.view.EntryAdapter;
-import github.daneren2005.dsub.view.MergeAdapter;
-import github.daneren2005.dsub.util.TabBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-
-public class SearchFragment extends SubsonicFragment {
- 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);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.search, container, false);
- setTitle(R.string.search_title);
-
- View buttons = inflater.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) rootView.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) {
- context.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);
- ((SearchActivity)context).onSupportNewIntent(context.getIntent());
- return rootView;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.search, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- if(super.onOptionsItemSelected(item)) {
- return true;
- }
-
- return false;
- }
-
- @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);
- onCreateContextMenu(menu, view, menuInfo, selectedItem);
- if(selectedItem instanceof MusicDirectory.Entry && !((MusicDirectory.Entry) selectedItem).isVideo() && !Util.isOffline(context)) {
- menu.removeItem(R.id.song_menu_remove_playlist);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- if(!primaryFragment) {
- return false;
- }
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- Object selectedItem = list.getItemAtPosition(info.position);
-
- if(onContextItemSelected(menuItem, selectedItem)) {
- return true;
- }
-
- return true;
- }
-
- @Override
- public void setPrimaryFragment(boolean primary) {
- super.setPrimaryFragment(primary);
- if(rootView != null && primary) {
- ((SearchActivity)context).onSupportNewIntent(context.getIntent());
- }
- }
-
- public void search(final String query, final boolean autoplay) {
- mergeAdapter = new MergeAdapter();
- list.setAdapter(mergeAdapter);
-
- BackgroundTask<SearchResult> task = new TabBackgroundTask<SearchResult>(this) {
- @Override
- protected SearchResult doInBackground() throws Throwable {
- SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS);
- MusicService service = MusicServiceFactory.getMusicService(context);
- return service.search(criteria, context, this);
- }
-
- @Override
- protected void done(SearchResult result) {
- searchResult = result;
- populateList();
- if (autoplay) {
- autoplay();
- }
-
- }
- };
- task.execute();
- }
-
- public 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(context, 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(context, 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(context, 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) {
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.search_layout);
- }
-
- private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) {
- int id = R.id.search_layout;
- Bundle args;
- if(album.getParent() != null) {
- SubsonicFragment parentFragment = new SelectDirectoryFragment();
- args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ID, album.getParent());
- args.putString(Constants.INTENT_EXTRA_NAME_NAME, album.getArtist());
- parentFragment.setArguments(args);
-
- replaceFragment(parentFragment, R.id.search_layout);
- id = parentFragment.getRootId();
- }
-
- SubsonicFragment fragment = new SelectDirectoryFragment();
- args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ID, album.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle());
- fragment.setArguments(args);
-
- replaceFragment(fragment, id);
- }
-
- 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, false);
- if (autoplay) {
- downloadService.play(downloadService.size() - 1);
- }
-
- Util.toast(context, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1));
- }
- }
-
- private void onVideoSelected(MusicDirectory.Entry entry) {
- int maxBitrate = Util.getMaxVideoBitrate(context);
-
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoUrl(maxBitrate, context, 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);
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java deleted file mode 100644 index 0a35233e..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java +++ /dev/null @@ -1,208 +0,0 @@ -package github.daneren2005.dsub.fragments;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import com.actionbarsherlock.view.Menu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Artist;
-import github.daneren2005.dsub.domain.Indexes;
-import github.daneren2005.dsub.domain.MusicFolder;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.util.BackgroundTask;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.TabBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.ArtistAdapter;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-public class SelectArtistFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
- private static final String TAG = SelectArtistFragment.class.getSimpleName();
- private static final int MENU_GROUP_MUSIC_FOLDER = 10;
-
- private ListView artistList;
- private View folderButtonParent;
- private View folderButton;
- private TextView folderName;
- private List<MusicFolder> musicFolders = null;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_artist, container, false);
-
- artistList = (ListView) rootView.findViewById(R.id.select_artist_list);
- artistList.setOnItemClickListener(this);
-
- folderButtonParent = inflater.inflate(R.layout.select_artist_header, artistList, false);
- folderName = (TextView) folderButtonParent.findViewById(R.id.select_artist_folder_2);
- artistList.addHeaderView(folderButtonParent);
- folderButton = folderButtonParent.findViewById(R.id.select_artist_folder);
-
- registerForContextMenu(artistList);
- if(!primaryFragment) {
- invalidated = true;
- } else {
- refresh(false);
- }
-
- return rootView;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.select_artist, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- if(super.onOptionsItemSelected(item)) {
- return true;
- }
-
- return false;
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- Object entry = artistList.getItemAtPosition(info.position);
-
- if (entry instanceof Artist) {
- onCreateContextMenu(menu, view, menuInfo, entry);
- } else if (info.position == 0) {
- String musicFolderId = Util.getSelectedMusicFolderId(context);
- 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) {
- if(!primaryFragment) {
- return false;
- }
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- Artist artist = (Artist) artistList.getItemAtPosition(info.position);
-
- if (artist != null) {
- return onContextItemSelected(menuItem, artist);
- } 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 ? context.getString(R.string.select_artist_all_folders)
- : selectedFolder.getName();
- Util.setSelectedMusicFolderId(context, musicFolderId);
- folderName.setText(musicFolderName);
- refresh();
- }
-
- return true;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (view == folderButtonParent) {
- selectFolder();
- } else {
- Artist artist = (Artist) parent.getItemAtPosition(position);
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.select_artist_layout);
- }
- }
-
- @Override
- protected void refresh(boolean refresh) {
- load(refresh);
- }
-
- private void load(final boolean refresh) {
- setTitle(R.string.search_artists);
-
- if (Util.isOffline(context)) {
- folderButton.setVisibility(View.GONE);
- } else {
- folderButton.setVisibility(View.VISIBLE);
- }
- artistList.setVisibility(View.INVISIBLE);
-
- BackgroundTask<Indexes> task = new TabBackgroundTask<Indexes>(this) {
- @Override
- protected Indexes doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- if (!Util.isOffline(context)) {
- musicFolders = musicService.getMusicFolders(refresh, context, this);
- }
- String musicFolderId = Util.getSelectedMusicFolderId(context);
- return musicService.getIndexes(musicFolderId, refresh, context, 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(context, artists));
-
- // Display selected music folder
- if (musicFolders != null) {
- String musicFolderId = Util.getSelectedMusicFolderId(context);
- 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;
- }
- }
- }
- }
- artistList.setVisibility(View.VISIBLE);
- }
- };
- task.execute();
- }
-
- private void selectFolder() {
- folderButton.showContextMenu();
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java deleted file mode 100644 index c3771492..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ /dev/null @@ -1,818 +0,0 @@ -package github.daneren2005.dsub.fragments;
-
-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.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.Button;
-import android.widget.ListView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.view.EntryAdapter;
-import java.util.List;
-import com.mobeta.android.dslv.*;
-import github.daneren2005.dsub.activity.DownloadActivity;
-import github.daneren2005.dsub.activity.SearchActivity;
-import github.daneren2005.dsub.domain.PodcastEpisode;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.service.OfflineException;
-import github.daneren2005.dsub.service.ServerTooOldException;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.LoadingTask;
-import github.daneren2005.dsub.util.Pair;
-import github.daneren2005.dsub.util.TabBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.AlbumListAdapter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-public class SelectDirectoryFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
- private static final String TAG = SelectDirectoryFragment.class.getSimpleName();
-
- private DragSortListView entryList;
- int rootId;
- private View footer;
- private View emptyView;
- private boolean hideButtons = false;
- private Boolean licenseValid;
- private boolean showHeader = true;
- private EntryAdapter entryAdapter;
- private List<MusicDirectory.Entry> entries;
-
- String id;
- String name;
- String playlistId;
- String playlistName;
- String podcastId;
- String podcastName;
- String podcastDescription;
- String albumListType;
- String albumListExtra;
- int albumListSize;
-
-
- public SelectDirectoryFragment() {
- super();
- rootId = getNewId();
- }
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- if(bundle != null) {
- int tmp = bundle.getInt(Constants.FRAGMENT_ID, -1);
- if(tmp > 0) {
- rootId = tmp;
- }
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putInt(Constants.FRAGMENT_ID, rootId);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_album, container, false);
- rootView.setId(rootId);
-
- entryList = (DragSortListView) rootView.findViewById(R.id.select_album_entries);
- footer = LayoutInflater.from(context).inflate(R.layout.select_album_footer, entryList, false);
- entryList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- entryList.setOnItemClickListener(this);
- entryList.setDropListener(new DragSortListView.DropListener() {
- @Override
- public void drop(int from, int to) {
- int max = entries.size();
- if(to >= max) {
- to = max - 1;
- }
- else if(to < 0) {
- to = 0;
- }
- entries.add(to, entries.remove(from));
- entryAdapter.notifyDataSetChanged();
- }
- });
-
- emptyView = rootView.findViewById(R.id.select_album_empty);
-
- registerForContextMenu(entryList);
-
- Bundle args = getArguments();
- if(args != null) {
- id = args.getString(Constants.INTENT_EXTRA_NAME_ID);
- name = args.getString(Constants.INTENT_EXTRA_NAME_NAME);
- playlistId = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
- playlistName = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
- podcastId = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_ID);
- podcastName = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME);
- podcastDescription = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION);
- albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
- albumListExtra = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA);
- albumListSize = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
- }
- if(primaryFragment) {
- load(false);
- } else {
- invalidated = true;
- }
- if(name != null) {
- setTitle(name);
- }
-
- return rootView;
- }
-
- @Override
- public void onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
- if(licenseValid == null) {
- menuInflater.inflate(R.menu.empty, menu);
- }
- else if(hideButtons) {
- if(albumListType != null) {
- menuInflater.inflate(R.menu.select_album_list, menu);
- } else {
- menuInflater.inflate(R.menu.select_album, menu);
- }
- } else {
- if(podcastId == null) {
- if(Util.isOffline(context)) {
- menuInflater.inflate(R.menu.select_song_offline, menu);
- }
- else {
- menuInflater.inflate(R.menu.select_song, menu);
-
- if(playlistId == null) {
- menu.removeItem(R.id.menu_remove_playlist);
- }
- }
- } else {
- if(Util.isOffline(context)) {
- menuInflater.inflate(R.menu.select_podcast_episode_offline, menu);
- }
- else {
- menuInflater.inflate(R.menu.select_podcast_episode, menu);
- }
- }
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_play_now:
- playNow(false, false);
- return true;
- case R.id.menu_play_last:
- playNow(false, true);
- return true;
- case R.id.menu_shuffle:
- playNow(true, false);
- return true;
- case R.id.menu_select:
- selectAllOrNone();
- return true;
- case R.id.menu_download:
- downloadBackground(false);
- selectAll(false, false);
- return true;
- case R.id.menu_cache:
- downloadBackground(true);
- selectAll(false, false);
- return true;
- case R.id.menu_delete:
- delete();
- selectAll(false, false);
- return true;
- case R.id.menu_add_playlist:
- addToPlaylist(getSelectedSongs());
- return true;
- case R.id.menu_remove_playlist:
- removeFromPlaylist(playlistId, playlistName, getSelectedIndexes());
- return true;
- }
-
- if(super.onOptionsItemSelected(item)) {
- return true;
- }
-
- return false;
- }
-
- @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);
- onCreateContextMenu(menu, view, menuInfo, entry);
- if(!entry.isVideo() && !Util.isOffline(context) && playlistId == null && (podcastId == null || Util.isOffline(context) && podcastId != null)) {
- menu.removeItem(R.id.song_menu_remove_playlist);
- }
- if(podcastId != null && !Util.isOffline(context)) {
- String status = ((PodcastEpisode)entry).getStatus();
- if("completed".equals(status)) {
- menu.removeItem(R.id.song_menu_server_download);
- }
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- if(!primaryFragment) {
- return false;
- }
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- Object selectedItem = entries.get(showHeader ? (info.position - 1) : info.position);
-
- if(onContextItemSelected(menuItem, selectedItem)) {
- return true;
- }
-
- switch (menuItem.getItemId()) {
- case R.id.song_menu_remove_playlist:
- removeFromPlaylist(playlistId, playlistName, Arrays.<Integer>asList(info.position - 1));
- break;
- case R.id.song_menu_server_download:
- downloadPodcastEpisode((PodcastEpisode)selectedItem);
- break;
- case R.id.song_menu_server_delete:
- deletePodcastEpisode((PodcastEpisode)selectedItem);
- break;
- }
-
- return true;
- }
-
- @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()) {
- int fragId = rootId;
- if(albumListType != null && entry.getParent() != null) {
- SubsonicFragment parentFragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getParent());
- args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getArtist());
- parentFragment.setArguments(args);
-
- replaceFragment(parentFragment, fragId);
- fragId = parentFragment.getRootId();
- }
-
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle());
- fragment.setArguments(args);
-
- replaceFragment(fragment, fragId);
- } else if (entry.isVideo()) {
- playVideo(entry);
- } else if(entry instanceof PodcastEpisode) {
- String status = ((PodcastEpisode)entry).getStatus();
- if("error".equals(status)) {
- Util.toast(context, R.string.select_podcasts_error);
- return;
- } else if(!"completed".equals(status)) {
- Util.toast(context, R.string.select_podcasts_skipped);
- return;
- }
-
- getDownloadService().clear();
- List<MusicDirectory.Entry> podcasts = new ArrayList<MusicDirectory.Entry>(1);
- podcasts.add(entry);
- getDownloadService().download(podcasts, false, true, true, false);
- Util.startActivityWithoutTransition(context, DownloadActivity.class);
- }
- }
- }
-
- @Override
- protected void refresh(boolean refresh) {
- load(refresh);
- }
-
- @Override
- public int getRootId() {
- return rootId;
- }
-
- private void load(boolean refresh) {
- entryList.setVisibility(View.INVISIBLE);
- emptyView.setVisibility(View.INVISIBLE);
- if (playlistId != null) {
- getPlaylist(playlistId, playlistName);
- } else if(podcastId != null) {
- getPodcast(podcastId, podcastName);
- } else if (albumListType != null) {
- getAlbumList(albumListType, albumListSize);
- } else {
- getMusicDirectory(id, name, refresh);
- }
- }
-
- private void getMusicDirectory(final String id, final String name, final boolean refresh) {
- setTitle(name);
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- return service.getMusicDirectory(id, name, refresh, context, 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, context, this);
- }
- }.execute();
- }
-
- private void getPodcast(final String podcastId, final String podcastName) {
- setTitle(podcastName);
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- return service.getPodcastEpisodes(podcastId, context, this);
- }
- }.execute();
- }
-
- private void getAlbumList(final String albumListType, final int size) {
- showHeader = false;
-
- 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);
- } else if ("starred".equals(albumListType)) {
- setTitle(R.string.main_albums_starred);
- } else if("genres".equals(albumListType)) {
- setTitle(albumListExtra);
- }
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- MusicDirectory result;
- if ("starred".equals(albumListType)) {
- result = service.getStarredList(context, this);
- } else if("genres".equals(albumListType)) {
- result = service.getSongsByGenre(albumListExtra, size, 0, context, this);
- } else {
- result = service.getAlbumList(albumListType, size, 0, context, this);
- }
- return result;
- }
- }.execute();
- }
-
- private abstract class LoadTask extends TabBackgroundTask<Pair<MusicDirectory, Boolean>> {
-
- public LoadTask() {
- super(SelectDirectoryFragment.this);
- }
-
- protected abstract MusicDirectory load(MusicService service) throws Exception;
-
- @Override
- protected Pair<MusicDirectory, Boolean> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- MusicDirectory dir = load(musicService);
- boolean valid = musicService.isLicenseValid(context, this);
- return new Pair<MusicDirectory, Boolean>(dir, valid);
- }
-
- @Override
- protected void done(Pair<MusicDirectory, Boolean> result) {
- entries = result.getFirst().getChildren();
-
- int songCount = 0;
- for (MusicDirectory.Entry entry : entries) {
- if (!entry.isDirectory()) {
- songCount++;
- }
- }
-
- if (songCount > 0) {
- if(showHeader) {
- View header = createHeader(entries);
- if(header != null) {
- entryList.addHeaderView(header, null, false);
- }
- }
- } else {
- showHeader = false;
- hideButtons = true;
- }
-
- emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE);
- entryAdapter = new EntryAdapter(context, getImageLoader(), entries, (podcastId == null) ? true : false);
- if(albumListType == null || "starred".equals(albumListType)) {
- entryList.setAdapter(entryAdapter);
- } else {
- entryList.setAdapter(new AlbumListAdapter(context, entryAdapter, albumListType, albumListExtra, albumListSize));
- }
- entryList.setVisibility(View.VISIBLE);
- licenseValid = result.getSecond();
- context.invalidateOptionsMenu();
-
- Bundle args = getArguments();
- boolean playAll = args.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
- if (playAll && songCount > 0) {
- playAll(args.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false), false);
- }
- }
- }
-
- private void playNow(final boolean shuffle, final boolean append) {
- if(getSelectedSongs().size() > 0) {
- download(append, false, !append, false, shuffle);
- selectAll(false, false);
- }
- else {
- playAll(shuffle, append);
- }
- }
- private void playAll(final boolean shuffle, final boolean append) {
- 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;
- }
- }
-
- if (hasSubFolders && id != null) {
- downloadRecursively(id, false, append, !append, shuffle, false);
- } else {
- selectAll(true, false);
- download(append, false, !append, false, shuffle);
- selectAll(false, false);
- }
- }
-
- 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(context, context.getString(toastResId, selectedCount));
- }
- }
-
- 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 List<Integer> getSelectedIndexes() {
- List<Integer> indexes = new ArrayList<Integer>();
-
- int count = entryList.getCount();
- for (int i = 0; i < count; i++) {
- if (entryList.isItemChecked(i)) {
- indexes.add(i - 1);
- }
- }
-
- return indexes;
- }
-
- private void download(final boolean append, final boolean save, final boolean autoplay, final boolean playNext, final boolean shuffle) {
- 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, shuffle);
- if (playlistName != null) {
- getDownloadService().setSuggestedPlaylistName(playlistName, playlistId);
- } else {
- getDownloadService().setSuggestedPlaylistName(null, null);
- }
- if (autoplay) {
- Util.startActivityWithoutTransition(context, DownloadActivity.class);
- if(context instanceof SearchActivity) {
- context.finish();
- }
- } else if (save) {
- Util.toast(context,
- context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
- } else if (append) {
- Util.toast(context,
- context.getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size()));
- }
- }
- };
-
- checkLicenseAndTrialPeriod(onValid);
- }
- private void downloadBackground(final boolean save) {
- List<MusicDirectory.Entry> songs = getSelectedSongs();
- if(songs.isEmpty()) {
- selectAll(true, false);
- songs = getSelectedSongs();
- }
- downloadBackground(save, songs);
- }
- private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs) {
- if (getDownloadService() == null) {
- return;
- }
-
- Runnable onValid = new Runnable() {
- @Override
- public void run() {
- warnIfNetworkOrStorageUnavailable();
- getDownloadService().downloadBackground(songs, save);
-
- Util.toast(context,
- context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
- }
- };
-
- checkLicenseAndTrialPeriod(onValid);
- }
-
- private void delete() {
- List<MusicDirectory.Entry> songs = getSelectedSongs();
- if(songs.isEmpty()) {
- selectAll(true, false);
- songs = getSelectedSongs();
- }
- if (getDownloadService() != null) {
- getDownloadService().delete(songs);
- }
- }
-
- public void removeFromPlaylist(final String id, final String name, final List<Integer> indexes) {
- new LoadingTask<Void>(context, true) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.removeFromPlaylist(id, indexes, context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- for(int i = indexes.size() - 1; i >= 0; i--) {
- entryList.setItemChecked(indexes.get(i) + 1, false);
- entryAdapter.removeAt(indexes.get(i));
- }
- entryAdapter.notifyDataSetChanged();
- Util.toast(context, context.getResources().getString(R.string.removed_playlist, indexes.size(), name));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.updated_playlist_error, name) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
-
- public void downloadPodcastEpisode(final PodcastEpisode episode) {
- new LoadingTask<Void>(context, true) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.downloadPodcastEpisode(episode.getEpisodeId(), context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(context, context.getResources().getString(R.string.select_podcasts_downloading, episode.getTitle()));
- }
-
- @Override
- protected void error(Throwable error) {
- Util.toast(context, getErrorMessage(error), false);
- }
- }.execute();
- }
-
- public void deletePodcastEpisode(final PodcastEpisode episode) {
- Util.confirmDialog(context, R.string.common_delete, episode.getTitle(), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new LoadingTask<Void>(context, true) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.deletePodcastEpisode(episode.getEpisodeId(), context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- entries.remove(episode);
- entryAdapter.notifyDataSetChanged();
- }
-
- @Override
- protected void error(Throwable error) {
- Util.toast(context, getErrorMessage(error), false);
- }
- }.execute();
- }
- });
- }
-
- private void checkLicenseAndTrialPeriod(Runnable onValid) {
- if (licenseValid) {
- onValid.run();
- return;
- }
-
- int trialDaysLeft = Util.getRemainingTrialDays(context);
- 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(context, context.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(context);
- 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(context.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 View createHeader(List<MusicDirectory.Entry> entries) {
- View header = entryList.findViewById(R.id.select_album_header);
- boolean add = false;
- if(header == null) {
- header = LayoutInflater.from(context).inflate(R.layout.select_album_header, entryList, false);
- add = true;
- }
-
- View coverArtView = header.findViewById(R.id.select_album_art);
- getImageLoader().loadImage(coverArtView, entries.get(random.nextInt(entries.size())), false, true);
-
- TextView titleView = (TextView) header.findViewById(R.id.select_album_title);
- if(playlistName != null) {
- titleView.setText(playlistName);
- } else if(podcastName != null) {
- titleView.setText(podcastName);
- titleView.setPadding(0, 6, 4, 8);
- } else if(name != null) {
- titleView.setText(name);
- }
-
- int songCount = 0;
-
- Set<String> artists = new HashSet<String>();
- Integer totalDuration = 0;
- for (MusicDirectory.Entry entry : entries) {
- if (!entry.isDirectory()) {
- songCount++;
- if (entry.getArtist() != null) {
- artists.add(entry.getArtist());
- }
- Integer duration = entry.getDuration();
- if(duration != null) {
- totalDuration += duration;
- }
- }
- }
-
- TextView artistView = (TextView) header.findViewById(R.id.select_album_artist);
- if(podcastDescription != null) {
- artistView.setText(podcastDescription);
- artistView.setSingleLine(false);
- artistView.setLines(5);
- } else if (artists.size() == 1) {
- artistView.setText(artists.iterator().next());
- artistView.setVisibility(View.VISIBLE);
- } else {
- artistView.setVisibility(View.GONE);
- }
-
- TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count);
- TextView songLengthView = (TextView) header.findViewById(R.id.select_album_song_length);
- if(podcastDescription == null) {
- String s = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
- songCountView.setText(s.toUpperCase());
- songLengthView.setText(Util.formatDuration(totalDuration));
- } else {
- songCountView.setVisibility(View.GONE);
- songLengthView.setVisibility(View.GONE);
- }
-
- if(add) {
- return header;
- } else {
- return null;
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java deleted file mode 100644 index 623aba4e..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectGenreFragment.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 2010 (C) Sindre Mehus
- */
-package github.daneren2005.dsub.fragments;
-
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Genre;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.util.BackgroundTask;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.TabBackgroundTask;
-import github.daneren2005.dsub.view.GenreAdapter;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuItem;
-import com.actionbarsherlock.view.MenuInflater;
-import java.util.ArrayList;
-import java.util.List;
-
-public class SelectGenreFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
- private static final String TAG = SelectGenreFragment.class.getSimpleName();
- private ListView genreListView;
- private View emptyView;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_genres, container, false);
-
- genreListView = (ListView)rootView.findViewById(R.id.select_genre_list);
- genreListView.setOnItemClickListener(this);
- emptyView = rootView.findViewById(R.id.select_genre_empty);
- refresh();
-
- return rootView;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.select_genres, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if(super.onOptionsItemSelected(item)) {
- return true;
- }
-
- return false;
- }
-
- @Override
- public void setPrimaryFragment(boolean primary) {
- super.setPrimaryFragment(primary);
- if(rootView != null) {
- if(primary) {
- ((ViewGroup)rootView).getChildAt(0).setVisibility(View.VISIBLE);
- } else {
- ((ViewGroup)rootView).getChildAt(0).setVisibility(View.GONE);
- }
- }
- }
-
- @Override
- protected void refresh(boolean refresh) {
- load(refresh);
- }
-
- private void load(final boolean refresh) {
- setTitle(R.string.main_albums_genres);
- genreListView.setVisibility(View.INVISIBLE);
-
- BackgroundTask<List<Genre>> task = new TabBackgroundTask<List<Genre>>(this) {
- @Override
- protected List<Genre> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
-
- List<Genre> genres = new ArrayList<Genre>();
-
- try {
- genres = musicService.getGenres(refresh, context, this);
- } catch (Exception x) {
- Log.e(TAG, "Failed to load genres", x);
- }
-
- return genres;
- }
-
- @Override
- protected void done(List<Genre> result) {
- emptyView.setVisibility(result == null || result.isEmpty() ? View.VISIBLE : View.GONE);
-
- if (result != null) {
- genreListView.setAdapter(new GenreAdapter(context, result));
- genreListView.setVisibility(View.VISIBLE);
- }
- }
- };
- task.execute();
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- Genre genre = (Genre) parent.getItemAtPosition(position);
-
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "genres");
- args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20);
- args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
- args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, genre.getName());
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.select_genre_layout);
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java deleted file mode 100644 index de74cdb2..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java +++ /dev/null @@ -1,286 +0,0 @@ -package github.daneren2005.dsub.fragments;
-
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.FragmentTransaction;
-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.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ListView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Playlist;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.service.OfflineException;
-import github.daneren2005.dsub.service.ServerTooOldException;
-import github.daneren2005.dsub.util.BackgroundTask;
-import github.daneren2005.dsub.util.CacheCleaner;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.LoadingTask;
-import github.daneren2005.dsub.util.TabBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.PlaylistAdapter;
-import java.util.List;
-
-public class SelectPlaylistFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
- private static final String TAG = SelectPlaylistFragment.class.getSimpleName();
-
- private ListView list;
- private View emptyTextView;
- private PlaylistAdapter playlistAdapter;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_playlist, container, false);
-
- list = (ListView) rootView.findViewById(R.id.select_playlist_list);
- emptyTextView = rootView.findViewById(R.id.select_playlist_empty);
- list.setOnItemClickListener(this);
- registerForContextMenu(list);
- if(!primaryFragment) {
- invalidated = true;
- } else {
- refresh(false);
- }
-
- return rootView;
- }
-
- @Override
- public void onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.select_playlist, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- if(super.onOptionsItemSelected(item)) {
- return true;
- }
-
- return false;
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- MenuInflater inflater = context.getMenuInflater();
- if (Util.isOffline(context)) {
- inflater.inflate(R.menu.select_playlist_context_offline, menu);
- }
- else {
- inflater.inflate(R.menu.select_playlist_context, menu);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- if(!primaryFragment) {
- return false;
- }
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- Playlist playlist = (Playlist) list.getItemAtPosition(info.position);
-
- SubsonicFragment fragment;
- Bundle args;
- FragmentTransaction trans;
- switch (menuItem.getItemId()) {
- case R.id.playlist_menu_download:
- downloadPlaylist(playlist.getId(), playlist.getName(), false, true, false, false, true);
- break;
- case R.id.playlist_menu_pin:
- downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true);
- break;
- case R.id.playlist_menu_play_now:
- fragment = new SelectDirectoryFragment();
- args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
- args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.select_playlist_layout);
- break;
- case R.id.playlist_menu_play_shuffled:
- fragment = new SelectDirectoryFragment();
- args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
- args.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.select_playlist_layout);
- break;
- case R.id.playlist_menu_delete:
- deletePlaylist(playlist);
- break;
- case R.id.playlist_info:
- displayPlaylistInfo(playlist);
- break;
- case R.id.playlist_update_info:
- updatePlaylistInfo(playlist);
- break;
- default:
- return false;
- }
- return true;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- Playlist playlist = (Playlist) parent.getItemAtPosition(position);
-
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.select_playlist_layout);
- }
-
- @Override
- protected void refresh(boolean refresh) {
- load(refresh);
- }
-
- private void load(final boolean refresh) {
- setTitle(R.string.playlist_label);
- list.setVisibility(View.INVISIBLE);
-
- BackgroundTask<List<Playlist>> task = new TabBackgroundTask<List<Playlist>>(this) {
- @Override
- protected List<Playlist> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- List<Playlist> playlists = musicService.getPlaylists(refresh, context, this);
- if(!Util.isOffline(context) && refresh) {
- new CacheCleaner(context, getDownloadService()).cleanPlaylists(playlists);
- }
- return playlists;
- }
-
- @Override
- protected void done(List<Playlist> result) {
- list.setAdapter(playlistAdapter = new PlaylistAdapter(context, result));
- emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE);
- list.setVisibility(View.VISIBLE);
- }
- };
- task.execute();
- }
-
- private void deletePlaylist(final Playlist playlist) {
- Util.confirmDialog(context, R.string.common_delete, playlist.getName(), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new LoadingTask<Void>(context, false) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.deletePlaylist(playlist.getId(), context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- playlistAdapter.remove(playlist);
- playlistAdapter.notifyDataSetChanged();
- Util.toast(context, context.getResources().getString(R.string.menu_deleted_playlist, playlist.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.menu_deleted_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
- });
- }
-
- private void displayPlaylistInfo(final Playlist playlist) {
- String message = "Owner: " + playlist.getOwner() + "\nComments: " +
- ((playlist.getComment() == null) ? "" : playlist.getComment()) +
- "\nSong Count: " + playlist.getSongCount() +
- ((playlist.getPublic() == null) ? "" : ("\nPublic: " + playlist.getPublic())) +
- "\nCreation Date: " + playlist.getCreated().replace('T', ' ');
- Util.info(context, playlist.getName(), message);
- }
-
- private void updatePlaylistInfo(final Playlist playlist) {
- View dialogView = context.getLayoutInflater().inflate(R.layout.update_playlist, null);
- final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_playlist_name);
- final EditText commentBox = (EditText)dialogView.findViewById(R.id.get_playlist_comment);
- final CheckBox publicBox = (CheckBox)dialogView.findViewById(R.id.get_playlist_public);
-
- nameBox.setText(playlist.getName());
- commentBox.setText(playlist.getComment());
- Boolean pub = playlist.getPublic();
- if(pub == null) {
- publicBox.setEnabled(false);
- } else {
- publicBox.setChecked(pub);
- }
-
- new AlertDialog.Builder(context)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(R.string.playlist_update_info)
- .setView(dialogView)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new LoadingTask<Void>(context, false) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.updatePlaylist(playlist.getId(), nameBox.getText().toString(), commentBox.getText().toString(), publicBox.isChecked(), context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- refresh();
- Util.toast(context, context.getResources().getString(R.string.playlist_updated_info, playlist.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.playlist_updated_info_error, playlist.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
-
- })
- .setNegativeButton(R.string.common_cancel, null)
- .show();
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java deleted file mode 100644 index f0f78569..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java +++ /dev/null @@ -1,310 +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 github.daneren2005.dsub.fragments;
-
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.text.SpannableString;
-import android.text.method.LinkMovementMethod;
-import android.text.util.Linkify;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.TextView;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuInflater;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.PodcastChannel;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.service.OfflineException;
-import github.daneren2005.dsub.service.ServerTooOldException;
-import github.daneren2005.dsub.util.BackgroundTask;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.LoadingTask;
-import github.daneren2005.dsub.util.SilentBackgroundTask;
-import github.daneren2005.dsub.util.TabBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.PodcastChannelAdapter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- *
- * @author Scott
- */
-public class SelectPodcastsFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
- private static final String TAG = SelectPodcastsFragment.class.getSimpleName();
- private ListView podcastListView;
- private PodcastChannelAdapter podcastAdapter;
- private View emptyView;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_podcasts, container, false);
-
- podcastListView = (ListView)rootView.findViewById(R.id.select_podcasts_list);
- podcastListView.setOnItemClickListener(this);
- registerForContextMenu(podcastListView);
- emptyView = rootView.findViewById(R.id.select_podcasts_empty);
- if(!primaryFragment) {
- invalidated = true;
- } else {
- refresh(false);
- }
-
- return rootView;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.select_podcasts, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- if(super.onOptionsItemSelected(item)) {
- return true;
- }
-
- switch (item.getItemId()) {
- case R.id.menu_check:
- refreshPodcasts();
- break;
- case R.id.menu_add_podcast:
- addNewPodcast();
- break;
- }
-
- return false;
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
- if(!Util.isOffline(context)) {
- android.view.MenuInflater inflater = context.getMenuInflater();
- inflater.inflate(R.menu.select_podcasts_context, menu);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- if(!primaryFragment) {
- return false;
- }
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- PodcastChannel channel = (PodcastChannel) podcastListView.getItemAtPosition(info.position);
-
- switch (menuItem.getItemId()) {
- case R.id.podcast_channel_info:
- displayPodcastInfo(channel);
- break;
- case R.id.podcast_channel_delete:
- deletePodcast(channel);
- break;
- }
-
- return true;
- }
-
- @Override
- protected void refresh(final boolean refresh) {
- setTitle(R.string.button_bar_podcasts);
- podcastListView.setVisibility(View.INVISIBLE);
-
- BackgroundTask<List<PodcastChannel>> task = new TabBackgroundTask<List<PodcastChannel>>(this) {
- @Override
- protected List<PodcastChannel> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
-
- List<PodcastChannel> channels = new ArrayList<PodcastChannel>();
-
- try {
- channels = musicService.getPodcastChannels(refresh, context, this);
- } catch (Exception x) {
- Log.e(TAG, "Failed to load podcasts", x);
- }
-
- return channels;
- }
-
- @Override
- protected void done(List<PodcastChannel> result) {
- emptyView.setVisibility(result == null || result.isEmpty() ? View.VISIBLE : View.GONE);
-
- if (result != null) {
- podcastListView.setAdapter(podcastAdapter = new PodcastChannelAdapter(context, result));
- podcastListView.setVisibility(View.VISIBLE);
- }
- }
- };
- task.execute();
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- PodcastChannel channel = (PodcastChannel) parent.getItemAtPosition(position);
-
- if("error".equals(channel.getStatus())) {
- Util.toast(context, context.getResources().getString(R.string.select_podcasts_invalid_podcast_channel, channel.getErrorMessage() == null ? "error" : channel.getErrorMessage()));
- } else if("downloading".equals(channel.getStatus())) {
- Util.toast(context, R.string.select_podcasts_initializing);
- } else {
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_ID, channel.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME, channel.getName());
- args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION, channel.getDescription());
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.select_podcasts_layout);
- }
- }
-
- public void refreshPodcasts() {
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.refreshPodcasts(context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(context, R.string.select_podcasts_refreshing);
- }
-
- @Override
- protected void error(Throwable error) {
- Util.toast(context, getErrorMessage(error), false);
- }
- }.execute();
- }
-
- private void addNewPodcast() {
- View dialogView = context.getLayoutInflater().inflate(R.layout.create_podcast, null);
- final TextView urlBox = (TextView) dialogView.findViewById(R.id.create_podcast_url);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.menu_add_podcast)
- .setView(dialogView)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- addNewPodcast(urlBox.getText().toString());
- }
- })
- .setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- })
- .setCancelable(true);
-
- AlertDialog dialog = builder.create();
- dialog.show();
- }
- private void addNewPodcast(final String url) {
- new LoadingTask<Void>(context, false) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.createPodcastChannel(url, context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- refresh();
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.select_podcasts_created_error) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
-
- private void displayPodcastInfo(final PodcastChannel channel) {
- String message = ((channel.getName()) == null ? "" : "Title: " + channel.getName()) +
- "\nURL: " + channel.getUrl() +
- "\nStatus: " + channel.getStatus() +
- ((channel.getErrorMessage()) == null ? "" : "\nError Message: " + channel.getErrorMessage()) +
- ((channel.getDescription()) == null ? "" : "\nDescription: " + channel.getDescription());
-
- Util.info(context, channel.getName(), message);
- }
-
- private void deletePodcast(final PodcastChannel channel) {
- Util.confirmDialog(context, R.string.common_delete, channel.getName(), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new LoadingTask<Void>(context, false) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.deletePodcastChannel(channel.getId(), context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- podcastAdapter.remove(channel);
- podcastAdapter.notifyDataSetChanged();
- Util.toast(context, context.getResources().getString(R.string.select_podcasts_deleted, channel.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.select_podcasts_deleted_error, channel.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
- });
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java deleted file mode 100644 index 9e8ec29c..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ /dev/null @@ -1,968 +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 github.daneren2005.dsub.fragments;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.media.MediaMetadataRetriever;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.TextView;
-import com.actionbarsherlock.app.SherlockFragment;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.activity.DownloadActivity;
-import github.daneren2005.dsub.activity.HelpActivity;
-import github.daneren2005.dsub.activity.MainActivity;
-import github.daneren2005.dsub.activity.SearchActivity;
-import github.daneren2005.dsub.activity.SettingsActivity;
-import github.daneren2005.dsub.activity.SubsonicActivity;
-import github.daneren2005.dsub.domain.Artist;
-import github.daneren2005.dsub.domain.Genre;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.Playlist;
-import github.daneren2005.dsub.domain.PodcastEpisode;
-import github.daneren2005.dsub.service.DownloadFile;
-import github.daneren2005.dsub.service.DownloadService;
-import github.daneren2005.dsub.service.DownloadServiceImpl;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.service.OfflineException;
-import github.daneren2005.dsub.service.ServerTooOldException;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.ImageLoader;
-import github.daneren2005.dsub.util.SilentBackgroundTask;
-import github.daneren2005.dsub.util.LoadingTask;
-import github.daneren2005.dsub.util.Util;
-import java.io.File;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Random;
-
-public class SubsonicFragment extends SherlockFragment {
- private static final String TAG = SubsonicFragment.class.getSimpleName();
- private static int internalID = Integer.MAX_VALUE;
- private static int TAG_INC = 10;
- private int tag;
-
- protected SubsonicActivity context;
- protected CharSequence title = "DSub";
- protected CharSequence subtitle = null;
- protected View rootView;
- protected boolean primaryFragment = false;
- protected boolean invalidated = false;
- protected static Random random = new Random();
-
- public SubsonicFragment() {
- super();
- tag = TAG_INC++;
- }
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- context = (SubsonicActivity)activity;
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_refresh:
- refresh(true);
- return true;
- case R.id.menu_shuffle:
- onShuffleRequested();
- return true;
- case R.id.menu_search:
- context.onSearchRequested();
- return true;
- case R.id.menu_exit:
- exit();
- return true;
- case R.id.menu_settings:
- startActivity(new Intent(context, SettingsActivity.class));
- return true;
- case R.id.menu_help:
- startActivity(new Intent(context, HelpActivity.class));
- return true;
- }
-
- return false;
- }
-
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo, Object selected) {
- MenuInflater inflater = context.getMenuInflater();
-
- if(selected instanceof MusicDirectory.Entry) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) selected;
- if(entry instanceof PodcastEpisode && !entry.isVideo()) {
- if(Util.isOffline(context)) {
- inflater.inflate(R.menu.select_podcast_episode_context_offline, menu);
- }
- else {
- inflater.inflate(R.menu.select_podcast_episode_context, menu);
- }
- }
- else if (entry.isDirectory()) {
- if(Util.isOffline(context)) {
- inflater.inflate(R.menu.select_album_context_offline, menu);
- }
- else {
- inflater.inflate(R.menu.select_album_context, menu);
- }
- menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star);
- } else if(!entry.isVideo()) {
- if(Util.isOffline(context)) {
- inflater.inflate(R.menu.select_song_context_offline, menu);
- }
- else {
- inflater.inflate(R.menu.select_song_context, menu);
- }
- menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star);
- } else {
- if(Util.isOffline(context)) {
- inflater.inflate(R.menu.select_video_context_offline, menu);
- }
- else {
- inflater.inflate(R.menu.select_video_context, menu);
- }
- }
- } else if(selected instanceof Artist) {
- if(Util.isOffline(context)) {
- inflater.inflate(R.menu.select_artist_context_offline, menu);
- }
- else {
- inflater.inflate(R.menu.select_artist_context, menu);
- }
- }
- }
-
- public boolean onContextItemSelected(MenuItem menuItem, Object selectedItem) {
- Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null;
- MusicDirectory.Entry entry = selectedItem instanceof MusicDirectory.Entry ? (MusicDirectory.Entry) selectedItem : null;
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
- songs.add(entry);
-
- switch (menuItem.getItemId()) {
- case R.id.artist_menu_play_now:
- downloadRecursively(artist.getId(), false, false, true, false, false);
- break;
- case R.id.artist_menu_play_shuffled:
- downloadRecursively(artist.getId(), false, false, true, true, false);
- break;
- case R.id.artist_menu_play_last:
- downloadRecursively(artist.getId(), false, true, false, false, false);
- break;
- case R.id.artist_menu_download:
- downloadRecursively(artist.getId(), false, true, false, false, true);
- break;
- case R.id.artist_menu_pin:
- downloadRecursively(artist.getId(), true, true, false, false, true);
- break;
- case R.id.artist_menu_delete:
- deleteRecursively(artist);
- break;
- case R.id.album_menu_play_now:
- downloadRecursively(entry.getId(), false, false, true, false, false);
- break;
- case R.id.album_menu_play_shuffled:
- downloadRecursively(entry.getId(), false, false, true, true, false);
- break;
- case R.id.album_menu_play_last:
- downloadRecursively(entry.getId(), false, true, false, false, false);
- break;
- case R.id.album_menu_download:
- downloadRecursively(entry.getId(), false, true, false, false, true);
- break;
- case R.id.album_menu_pin:
- downloadRecursively(entry.getId(), true, true, false, false, true);
- break;
- case R.id.album_menu_star:
- toggleStarred(entry);
- break;
- case R.id.album_menu_delete:
- deleteRecursively(entry);
- break;
- case R.id.song_menu_play_now:
- getDownloadService().clear();
- getDownloadService().download(songs, false, true, true, false);
- Util.startActivityWithoutTransition(context, DownloadActivity.class);
- if(context instanceof SearchActivity) {
- context.finish();
- }
- break;
- case R.id.song_menu_play_next:
- getDownloadService().download(songs, false, false, true, false);
- break;
- case R.id.song_menu_play_last:
- getDownloadService().download(songs, false, false, false, false);
- break;
- case R.id.song_menu_download:
- getDownloadService().downloadBackground(songs, false);
- break;
- case R.id.song_menu_pin:
- getDownloadService().downloadBackground(songs, true);
- break;
- case R.id.song_menu_delete:
- getDownloadService().delete(songs);
- break;
- case R.id.song_menu_add_playlist:
- addToPlaylist(songs);
- break;
- case R.id.song_menu_star:
- toggleStarred(entry);
- break;
- case R.id.song_menu_play_external:
- playExternalPlayer(entry);
- break;
- case R.id.song_menu_info:
- displaySongInfo(entry);
- break;
- case R.id.song_menu_stream_external:
- streamExternalPlayer(entry);
- break;
- default:
- return false;
- }
-
- return true;
- }
-
- public void replaceFragment(SubsonicFragment fragment, int id) {
- context.replaceFragment(fragment, id, fragment.getSupportTag());
- }
-
- protected int getNewId() {
- internalID--;
- return internalID;
- }
- public int getRootId() {
- return rootView.getId();
- }
-
- public int getSupportTag() {
- return tag;
- }
-
- public void setPrimaryFragment(boolean primary) {
- primaryFragment = primary;
- if(primary) {
- if(context != null) {
- context.setTitle(title);
- context.setSubtitle(subtitle);
- }
- if(invalidated) {
- invalidated = false;
- refresh(false);
- }
- }
- }
-
- public void invalidate() {
- if(primaryFragment) {
- refresh(false);
- } else {
- invalidated = true;
- }
- }
-
- public DownloadService getDownloadService() {
- return context != null ? context.getDownloadService() : null;
- }
-
- protected void refresh() {
- refresh(true);
- }
- protected void refresh(boolean refresh) {
-
- }
-
- protected void exit() {
- if(context.getClass() != MainActivity.class) {
- Intent intent = new Intent(context, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
- Util.startActivityWithoutTransition(context, intent);
- } else {
- context.stopService(new Intent(context, DownloadServiceImpl.class));
- context.finish();
- }
- }
-
- public void setProgressVisible(boolean visible) {
- View view = rootView.findViewById(R.id.tab_progress);
- if (view != null) {
- view.setVisibility(visible ? View.VISIBLE : View.GONE);
- }
- }
-
- public void updateProgress(String message) {
- TextView view = (TextView) rootView.findViewById(R.id.tab_progress_message);
- if (view != null) {
- view.setText(message);
- }
- }
-
- protected synchronized ImageLoader getImageLoader() {
- return context.getImageLoader();
- }
- public synchronized static ImageLoader getStaticImageLoader(Context context) {
- return SubsonicActivity.getStaticImageLoader(context);
- }
-
- public void setTitle(CharSequence title) {
- this.title = title;
- context.setTitle(title);
- }
- public void setTitle(int title) {
- this.title = context.getResources().getString(title);
- context.setTitle(this.title);
- }
- public void setSubtitle(CharSequence title) {
- this.subtitle = title;
- context.setSubtitle(title);
- }
- public CharSequence getTitle() {
- return this.title;
- }
-
- protected void warnIfNetworkOrStorageUnavailable() {
- if (!Util.isExternalStoragePresent()) {
- Util.toast(context, R.string.select_album_no_sdcard);
- } else if (!Util.isOffline(context) && !Util.isNetworkConnected(context)) {
- Util.toast(context, R.string.select_album_no_network);
- }
- }
-
- protected void onShuffleRequested() {
- if(Util.isOffline(context)) {
- Intent intent = new Intent(context, DownloadActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- Util.startActivityWithoutTransition(context, intent);
- return;
- }
-
- View dialogView = context.getLayoutInflater().inflate(R.layout.shuffle_dialog, null);
- final EditText startYearBox = (EditText)dialogView.findViewById(R.id.start_year);
- final EditText endYearBox = (EditText)dialogView.findViewById(R.id.end_year);
- final EditText genreBox = (EditText)dialogView.findViewById(R.id.genre);
- final Button genreCombo = (Button)dialogView.findViewById(R.id.genre_combo);
-
- final SharedPreferences prefs = Util.getPreferences(context);
- final String oldStartYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, "");
- final String oldEndYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "");
- final String oldGenre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, "");
-
- boolean _useCombo = false;
- if(Util.checkServerVersion(context, "1.9.0")) {
- genreBox.setVisibility(View.GONE);
- genreCombo.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- new LoadingTask<List<Genre>>(context, true) {
- @Override
- protected List<Genre> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- return musicService.getGenres(false, context, this);
- }
-
- @Override
- protected void done(final List<Genre> genres) {
- List<String> names = new ArrayList<String>();
- String blank = context.getResources().getString(R.string.select_genre_blank);
- names.add(blank);
- for(Genre genre: genres) {
- names.add(genre.getName());
- }
- final List<String> finalNames = names;
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.shuffle_pick_genre)
- .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- if(which == 0) {
- genreCombo.setText("");
- } else {
- genreCombo.setText(finalNames.get(which));
- }
- }
- });
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
- });
- _useCombo = true;
- } else {
- genreCombo.setVisibility(View.GONE);
- }
- final boolean useCombo = _useCombo;
-
- startYearBox.setText(oldStartYear);
- endYearBox.setText(oldEndYear);
- genreBox.setText(oldGenre);
- genreCombo.setText(oldGenre);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.shuffle_title)
- .setView(dialogView)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- Intent intent = new Intent(context, DownloadActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- String genre;
- if(useCombo) {
- genre = genreCombo.getText().toString();
- } else {
- genre = genreBox.getText().toString();
- }
- String startYear = startYearBox.getText().toString();
- String endYear = endYearBox.getText().toString();
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear);
- editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear);
- editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre);
- editor.commit();
-
- Util.startActivityWithoutTransition(context, intent);
- }
- })
- .setNegativeButton(R.string.common_cancel, null);
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- public void toggleStarred(final MusicDirectory.Entry entry) {
- final boolean starred = !entry.isStarred();
- entry.setStarred(starred);
-
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.setStarred(entry.getId(), starred, context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- // UpdateView
- Util.toast(context, context.getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getTitle()));
- }
-
- @Override
- protected void error(Throwable error) {
- entry.setStarred(!starred);
-
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.starring_content_error, entry.getTitle()) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
- public void toggleStarred(final Artist entry) {
- final boolean starred = !entry.isStarred();
- entry.setStarred(starred);
-
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.setStarred(entry.getId(), starred, context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- // UpdateView
- Util.toast(context, context.getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- entry.setStarred(!starred);
-
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.starring_content_error, entry.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
-
- protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) {
- downloadRecursively(id, "", true, save, append, autoplay, shuffle, background);
- }
- protected void downloadPlaylist(final String id, final String name, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) {
- downloadRecursively(id, name, false, save, append, autoplay, shuffle, background);
- }
- protected void downloadRecursively(final String id, final String name, final boolean isDirectory, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) {
- LoadingTask<List<MusicDirectory.Entry>> task = new LoadingTask<List<MusicDirectory.Entry>>(context) {
- private static final int MAX_SONGS = 500;
-
- @Override
- protected List<MusicDirectory.Entry> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- MusicDirectory root;
- if(isDirectory)
- root = musicService.getMusicDirectory(id, name, false, context, this);
- else
- root = musicService.getPlaylist(id, name, context, 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(context);
- getSongsRecursively(musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, context, this), songs);
- }
- }
-
- @Override
- protected void done(List<MusicDirectory.Entry> songs) {
- DownloadService downloadService = getDownloadService();
- if (!songs.isEmpty() && downloadService != null) {
- if (!append) {
- downloadService.clear();
- }
- warnIfNetworkOrStorageUnavailable();
- if(!background) {
- downloadService.download(songs, save, autoplay, false, shuffle);
- if(!append) {
- Util.startActivityWithoutTransition(context, DownloadActivity.class);
- if(context instanceof SearchActivity) {
- context.finish();
- }
- }
- }
- else {
- downloadService.downloadBackground(songs, save);
- }
- }
- }
- };
-
- task.execute();
- }
-
- protected void addToPlaylist(final List<MusicDirectory.Entry> songs) {
- if(songs.isEmpty()) {
- Util.toast(context, "No songs selected");
- return;
- }
-
- new LoadingTask<List<Playlist>>(context, true) {
- @Override
- protected List<Playlist> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- return musicService.getPlaylists(false, context, this);
- }
-
- @Override
- protected void done(final List<Playlist> playlists) {
- List<String> names = new ArrayList<String>();
- String createNew = context.getResources().getString(R.string.playlist_create_new);
- names.add(createNew);
- for(Playlist playlist: playlists) {
- names.add(playlist.getName());
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.playlist_add_to)
- .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
-
- if(which > 0) {
- addToPlaylist(playlists.get(which - 1), songs);
- } else {
- createNewPlaylist(songs, false);
- }
- }
- });
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
-
- private void addToPlaylist(final Playlist playlist, final List<MusicDirectory.Entry> songs) {
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.addToPlaylist(playlist.getId(), songs, context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(context, context.getResources().getString(R.string.updated_playlist, songs.size(), playlist.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.updated_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
-
- protected void createNewPlaylist(final List<MusicDirectory.Entry> songs, boolean getSuggestion) {
- View layout = context.getLayoutInflater().inflate(R.layout.save_playlist, null);
- final EditText playlistNameView = (EditText) layout.findViewById(R.id.save_playlist_name);
- final CheckBox overwriteCheckBox = (CheckBox) layout.findViewById(R.id.save_playlist_overwrite);
- if(getSuggestion) {
- String playlistName = (getDownloadService() != null) ? getDownloadService().getSuggestedPlaylistName() : null;
- if (playlistName != null) {
- playlistNameView.setText(playlistName);
- try {
- if(Util.checkServerVersion(context, "1.8.0") && Integer.parseInt(getDownloadService().getSuggestedPlaylistId()) != -1) {
- overwriteCheckBox.setChecked(true);
- overwriteCheckBox.setVisibility(View.VISIBLE);
- }
- } catch(Exception e) {
- Log.d(TAG, "Playlist id isn't a integer, probably MusicCabinet");
- }
- } else {
- DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
- playlistNameView.setText(dateFormat.format(new Date()));
- }
- } else {
- DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
- playlistNameView.setText(dateFormat.format(new Date()));
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.download_playlist_title)
- .setMessage(R.string.download_playlist_name)
- .setView(layout)
- .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- if(overwriteCheckBox.isChecked()) {
- overwritePlaylist(songs, String.valueOf(playlistNameView.getText()), getDownloadService().getSuggestedPlaylistId());
- } else {
- createNewPlaylist(songs, String.valueOf(playlistNameView.getText()));
- }
- }
- })
- .setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- })
- .setCancelable(true);
-
- AlertDialog dialog = builder.create();
- dialog.show();
- }
- private void createNewPlaylist(final List<MusicDirectory.Entry> songs, final String name) {
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- musicService.createPlaylist(null, name, songs, context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(context, R.string.download_playlist_done);
- }
-
- @Override
- protected void error(Throwable error) {
- String msg = context.getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error);
- Util.toast(context, msg);
- }
- }.execute();
- }
- private void overwritePlaylist(final List<MusicDirectory.Entry> songs, final String name, final String id) {
- new SilentBackgroundTask<Void>(context) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- MusicDirectory playlist = musicService.getPlaylist(id, name, context, null);
- List<MusicDirectory.Entry> toDelete = playlist.getChildren();
- musicService.overwritePlaylist(id, name, toDelete.size(), songs, context, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(context, R.string.download_playlist_done);
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = context.getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error);
- }
-
- Util.toast(context, msg, false);
- }
- }.execute();
- }
-
- public void displaySongInfo(final MusicDirectory.Entry song) {
- Integer bitrate = null;
- String format = null;
- long size = 0;
- try {
- DownloadFile downloadFile = new DownloadFile(context, song, false);
- File file = downloadFile.getCompleteFile();
- if(file.exists()) {
- MediaMetadataRetriever metadata = new MediaMetadataRetriever();
- metadata.setDataSource(file.getAbsolutePath());
- String tmp = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE);
- bitrate = Integer.parseInt((tmp != null) ? tmp : "0") / 1000;
- format = FileUtil.getExtension(file.getName());
- size = file.length();
-
- if(Util.isOffline(context)) {
- song.setGenre(metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
- String year = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
- song.setYear(Integer.parseInt((year != null) ? year : "0"));
- }
- }
- } catch(Exception e) {
- Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver");
- }
-
- String msg = "";
- if(song instanceof PodcastEpisode) {
- msg += "Podcast: " + song.getArtist() + "\nStatus: " + ((PodcastEpisode)song).getStatus();
- } else if(!song.isVideo()) {
- msg += "Artist: " + song.getArtist() + "\nAlbum: " + song.getAlbum();
- }
- if(song.getTrack() != null && song.getTrack() != 0) {
- msg += "\nTrack: " + song.getTrack();
- }
- if(song.getGenre() != null && !"".equals(song.getGenre())) {
- msg += "\nGenre: " + song.getGenre();
- }
- if(song.getYear() != null && song.getYear() != 0) {
- msg += "\nYear: " + song.getYear();
- }
- if(!Util.isOffline(context) && song.getSuffix() != null) {
- msg += "\nServer Format: " + song.getSuffix();
- if(song.getBitRate() != null && song.getBitRate() != 0) {
- msg += "\nServer Bitrate: " + song.getBitRate() + " kpbs";
- }
- }
- if(format != null && !"".equals(format)) {
- msg += "\nCached Format: " + format;
- }
- if(bitrate != null && bitrate != 0) {
- msg += "\nCached Bitrate: " + bitrate + " kpbs";
- }
- if(size != 0) {
- msg += "\nSize: " + Util.formatBytes(size);
- }
- if(song.getDuration() != null && song.getDuration() != 0) {
- msg += "\nLength: " + Util.formatDuration(song.getDuration());
- }
-
- Util.info(context, song.getTitle(), msg);
- }
-
- protected void playVideo(MusicDirectory.Entry entry) {
- if(entryExists(entry)) {
- playExternalPlayer(entry);
- } else {
- streamExternalPlayer(entry);
- }
- }
-
- protected void playWebView(MusicDirectory.Entry entry) {
- int maxBitrate = Util.getMaxVideoBitrate(context);
-
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoUrl(maxBitrate, context, entry.getId())));
-
- startActivity(intent);
- }
- protected void playExternalPlayer(MusicDirectory.Entry entry) {
- if(!entryExists(entry)) {
- Util.toast(context, R.string.download_need_download);
- } else {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.parse(entry.getPath()), "video/*");
-
- List<ResolveInfo> intents = context.getPackageManager()
- .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
- if(intents != null && intents.size() > 0) {
- startActivity(intent);
- }else {
- Util.toast(context, R.string.download_no_streaming_player);
- }
- }
- }
- protected void streamExternalPlayer(MusicDirectory.Entry entry) {
- String videoPlayerType = Util.getVideoPlayerType(context);
- if("flash".equals(videoPlayerType)) {
- playWebView(entry);
- } else if("hls".equals(videoPlayerType)) {
- streamExternalPlayer(entry, "hls");
- } else if("raw".equals(videoPlayerType)) {
- streamExternalPlayer(entry, "raw");
- } else {
- streamExternalPlayer(entry, entry.getTranscodedSuffix());
- }
- }
- protected void streamExternalPlayer(MusicDirectory.Entry entry, String format) {
- try {
- int maxBitrate = Util.getMaxVideoBitrate(context);
-
- Intent intent = new Intent(Intent.ACTION_VIEW);
- if("hls".equals(format)) {
- intent.setDataAndType(Uri.parse(MusicServiceFactory.getMusicService(context).getHlsUrl(entry.getId(), maxBitrate, context)), "video/*");
- } else {
- intent.setDataAndType(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoStreamUrl(format, maxBitrate, context, entry.getId())), "video/*");
- }
- intent.putExtra("title", entry.getTitle());
-
- List<ResolveInfo> intents = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
- if(intents != null && intents.size() > 0) {
- startActivity(intent);
- } else {
- Util.toast(context, R.string.download_no_streaming_player);
- }
- } catch(Exception error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = error.getMessage();
- } else {
- msg = context.getResources().getString(R.string.download_no_streaming_player) + " " + error.getMessage();
- }
-
- Util.toast(context, msg, false);
- }
- }
-
- protected boolean entryExists(MusicDirectory.Entry entry) {
- DownloadFile check = new DownloadFile(context, entry, false);
- return check.isCompleteFileAvailable();
- }
-
- public void deleteRecursively(Artist artist) {
- File dir = FileUtil.getArtistDirectory(context, artist);
- Util.recursiveDelete(dir);
- if(Util.isOffline(context)) {
- refresh();
- }
- }
-
- public void deleteRecursively(MusicDirectory.Entry album) {
- File dir = FileUtil.getAlbumDirectory(context, album);
- Util.recursiveDelete(dir);
- if(Util.isOffline(context)) {
- refresh();
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/provider/DSubSearchProvider.java b/subsonic-android/src/github/daneren2005/dsub/provider/DSubSearchProvider.java deleted file mode 100644 index 5ddec0f4..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/provider/DSubSearchProvider.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 github.daneren2005.dsub.provider; - -import android.content.SearchRecentSuggestionsProvider; - -/** - * Provides search suggestions based on recent searches. - * - * @author Sindre Mehus - */ -public class DSubSearchProvider extends SearchRecentSuggestionsProvider { - - public static final String AUTHORITY = DSubSearchProvider.class.getName(); - public static final int MODE = DATABASE_MODE_QUERIES; - - public DSubSearchProvider() { - setupSuggestions(AUTHORITY, MODE); - } -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x1.java b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x1.java deleted file mode 100644 index e00bf02d..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x1.java +++ /dev/null @@ -1,29 +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 github.daneren2005.dsub.provider;
-
-import android.appwidget.AppWidgetManager;
-import github.daneren2005.dsub.R;
-
-public class DSubWidget4x1 extends DSubWidgetProvider {
- @Override
- protected int getLayout() {
- return R.layout.appwidget4x1;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x2.java b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x2.java deleted file mode 100644 index 4908f632..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x2.java +++ /dev/null @@ -1,29 +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 github.daneren2005.dsub.provider;
-
-import android.appwidget.AppWidgetManager;
-import github.daneren2005.dsub.R;
-
-public class DSubWidget4x2 extends DSubWidgetProvider {
- @Override
- protected int getLayout() {
- return R.layout.appwidget4x2;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x3.java b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x3.java deleted file mode 100644 index f1908d0d..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x3.java +++ /dev/null @@ -1,29 +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 github.daneren2005.dsub.provider;
-
-import android.appwidget.AppWidgetManager;
-import github.daneren2005.dsub.R;
-
-public class DSubWidget4x3 extends DSubWidgetProvider {
- @Override
- protected int getLayout() {
- return R.layout.appwidget4x3;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x4.java b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x4.java deleted file mode 100644 index 7fee2747..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidget4x4.java +++ /dev/null @@ -1,29 +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 github.daneren2005.dsub.provider;
-
-import android.appwidget.AppWidgetManager;
-import github.daneren2005.dsub.R;
-
-public class DSubWidget4x4 extends DSubWidgetProvider {
- @Override
- protected int getLayout() {
- return R.layout.appwidget4x4;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java deleted file mode 100644 index 7215040c..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java +++ /dev/null @@ -1,277 +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 github.daneren2005.dsub.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 github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.DownloadActivity; -import github.daneren2005.dsub.activity.MainActivity; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.DownloadServiceImpl; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import java.util.HashMap; - -/** - * 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 DSubWidgetProvider extends AppWidgetProvider { - private static final String TAG = DSubWidgetProvider.class.getSimpleName(); - private static DSubWidget4x1 instance4x1; - private static DSubWidget4x2 instance4x2; - private static DSubWidget4x3 instance4x3; - private static DSubWidget4x4 instance4x4; - - public static synchronized void notifyInstances(Context context, DownloadService service, boolean playing) { - if(instance4x1 == null) { - instance4x1 = new DSubWidget4x1(); - } - if(instance4x2 == null) { - instance4x2 = new DSubWidget4x2(); - } - if(instance4x3 == null) { - instance4x3 = new DSubWidget4x3(); - } - if(instance4x4 == null) { - instance4x4 = new DSubWidget4x4(); - } - - instance4x1.notifyChange(context, service, playing); - instance4x2.notifyChange(context, service, playing); - instance4x3.notifyChange(context, service, playing); - instance4x4.notifyChange(context, service, playing); - } - - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - defaultAppWidget(context, appWidgetIds); - } - - protected int getLayout() { - return 0; - } - - /** - * 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(), getLayout()); - - views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text)); - if(getLayout() == R.layout.appwidget4x2) { - views.setTextViewText(R.id.album, ""); - } - - 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(), getLayout()); - - 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 album = currentPlaying == null ? null : currentPlaying.getAlbum(); - 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.setTextViewText(R.id.album, ""); - if(getLayout() != R.layout.appwidget4x1) { - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default); - } - } else { - // No error, so show normal titles - views.setTextViewText(R.id.title, title); - views.setTextViewText(R.id.artist, artist); - if(getLayout() != R.layout.appwidget4x1) { - views.setTextViewText(R.id.album, album); - } - } - - // 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; - if(getLayout() != R.layout.appwidget4x1 && getLayout() != R.layout.appwidget4x2) { - size = context.getResources().getDrawable(R.drawable.unknown_album_large).getIntrinsicHeight(); - } else { - 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, MainActivity.class); - if(playerActive) { - intent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - } - 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("DSub.PLAY_PAUSE"); - intent.setComponent(new ComponentName(context, DownloadServiceImpl.class)); - intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)); - pendingIntent = PendingIntent.getService(context, 0, intent, 0); - views.setOnClickPendingIntent(R.id.control_play, pendingIntent); - - intent = new Intent("DSub.NEXT"); // 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_UP, KeyEvent.KEYCODE_MEDIA_NEXT)); - pendingIntent = PendingIntent.getService(context, 0, intent, 0); - views.setOnClickPendingIntent(R.id.control_next, pendingIntent); - - intent = new Intent("DSub.PREVIOUS"); // 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_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS)); - pendingIntent = PendingIntent.getService(context, 0, intent, 0); - views.setOnClickPendingIntent(R.id.control_previous, pendingIntent); - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/receiver/A2dpIntentReceiver.java b/subsonic-android/src/github/daneren2005/dsub/receiver/A2dpIntentReceiver.java deleted file mode 100644 index c8c3a1f9..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/receiver/A2dpIntentReceiver.java +++ /dev/null @@ -1,48 +0,0 @@ -package github.daneren2005.dsub.receiver;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-import github.daneren2005.dsub.service.DownloadService;
-import github.daneren2005.dsub.service.DownloadServiceImpl;
-
-public class A2dpIntentReceiver extends BroadcastReceiver {
- private static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse";
- private String TAG = A2dpIntentReceiver.class.getSimpleName();
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i(TAG, "GOT INTENT " + intent);
-
- DownloadService downloadService = DownloadServiceImpl.getInstance();
-
- if (downloadService != null){
-
- Intent avrcpIntent = new Intent(PLAYSTATUS_RESPONSE);
-
- avrcpIntent.putExtra("duration", (long) downloadService.getPlayerDuration());
- avrcpIntent.putExtra("position", (long) downloadService.getPlayerPosition());
- avrcpIntent.putExtra("ListSize", (long) downloadService.getSongs().size());
-
- switch (downloadService.getPlayerState()){
- case STARTED:
- avrcpIntent.putExtra("playing", true);
- break;
- case STOPPED:
- avrcpIntent.putExtra("playing", false);
- break;
- case PAUSED:
- avrcpIntent.putExtra("playing", false);
- break;
- case COMPLETED:
- avrcpIntent.putExtra("playing", false);
- break;
- default:
- return;
- }
-
- context.sendBroadcast(avrcpIntent);
- }
- }
-}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/receiver/BluetoothIntentReceiver.java b/subsonic-android/src/github/daneren2005/dsub/receiver/BluetoothIntentReceiver.java deleted file mode 100644 index 567cf8f4..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/receiver/BluetoothIntentReceiver.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 github.daneren2005.dsub.receiver; - -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; -import github.daneren2005.dsub.service.DownloadServiceImpl; -import github.daneren2005.dsub.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(); - // Same as constants in android.bluetooth.BluetoothProfile, which is API level 11. - private static final int STATE_DISCONNECTED = 0; - private static final int STATE_CONNECTED = 2; - @Override - public void onReceive(Context context, Intent intent) { - Log.i(TAG, "GOT INTENT " + intent); - if (isConnected(intent)) { - Log.i(TAG, "Connected to Bluetooth A2DP, requesting media button focus."); - Util.registerMediaButtonEventReceiver(context); - } else if (isDisconnected(intent)) { - Log.i(TAG, "Disconnected from Bluetooth A2DP, requesting pause."); - context.sendBroadcast(new Intent(DownloadServiceImpl.CMD_PAUSE)); - } - } - private boolean isConnected(Intent intent) { - if ("android.bluetooth.a2dp.action.SINK_STATE_CHANGED".equals(intent.getAction()) && - intent.getIntExtra("android.bluetooth.a2dp.extra.SINK_STATE", -1) == STATE_CONNECTED) { - return true; - } - else if ("android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED".equals(intent.getAction()) && - intent.getIntExtra("android.bluetooth.profile.extra.STATE", -1) == STATE_CONNECTED) { - return true; - } - else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(intent.getAction())) { - return true; - } - return false; - } - private boolean isDisconnected(Intent intent) { - if ("android.bluetooth.a2dp.action.SINK_STATE_CHANGED".equals(intent.getAction()) && - intent.getIntExtra("android.bluetooth.a2dp.extra.SINK_STATE", -1) == STATE_DISCONNECTED) { - return true; - } - else if ("android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED".equals(intent.getAction()) && - intent.getIntExtra("android.bluetooth.profile.extra.STATE", -1) == STATE_DISCONNECTED) { - return true; - } - else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(intent.getAction())) { - return true; - } - return false; - } -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java b/subsonic-android/src/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java deleted file mode 100644 index 9ea04474..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java +++ /dev/null @@ -1,52 +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 github.daneren2005.dsub.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; -import android.view.KeyEvent; -import github.daneren2005.dsub.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); - if (isOrderedBroadcast()) - { - try { - abortBroadcast(); - } catch (Exception x) { - // Ignored. - } - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java deleted file mode 100644 index 943b5eb2..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java +++ /dev/null @@ -1,373 +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 github.daneren2005.dsub.service; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.apache.http.HttpResponse; - -import android.content.Context; -import android.graphics.Bitmap; -import android.support.v4.util.LruCache; -import github.daneren2005.dsub.domain.ChatMessage; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.JukeboxStatus; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.SearchCritera; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.domain.Version; -import github.daneren2005.dsub.util.CancellableTask; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.TimeLimitedCache; -import github.daneren2005.dsub.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>>(3600, TimeUnit.SECONDS); - private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS); - private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<List<Genre>>(10 * 3600, TimeUnit.SECONDS); - private final TimeLimitedCache<List<PodcastChannel>> cachedPodcastChannels = new TimeLimitedCache<List<PodcastChannel>>(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.evictAll(); - } - 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, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(id); - MusicDirectory dir = cache == null ? null : cache.get(); - if (dir == null) { - dir = musicService.getMusicDirectory(id, name, refresh, context, progressListener); - cache = new TimeLimitedCache<MusicDirectory>(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 { - cachedPlaylists.clear(); - musicService.createPlaylist(id, name, entries, context, progressListener); - } - - @Override - public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception { - musicService.deletePlaylist(id, context, progressListener); - } - - @Override - public void addToPlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception { - musicService.addToPlaylist(id, toAdd, context, progressListener); - } - - @Override - public void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception { - musicService.removeFromPlaylist(id, toRemove, context, progressListener); - } - - @Override - public void overwritePlaylist(String id, String name, int toRemove, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception { - musicService.overwritePlaylist(id, name, toRemove, toAdd, context, progressListener); - } - - @Override - public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception { - musicService.updatePlaylist(id, name, comment, pub, context, progressListener); - } - - @Override - public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception { - return musicService.getLyrics(artist, title, context, progressListener); - } - - @Override - public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception { - musicService.scrobble(id, submission, context, progressListener); - } - - @Override - public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { - return musicService.getAlbumList(type, size, offset, context, progressListener); - } - - @Override - public MusicDirectory getStarredList(Context context, ProgressListener progressListener) throws Exception { - return musicService.getStarredList(context, progressListener); - } - - @Override - public MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception { - return musicService.getRandomSongs(size, folder, genre, startYear, endYear, context, progressListener); - } - - @Override - public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, int saveSize, ProgressListener progressListener) throws Exception { - return musicService.getCoverArt(context, entry, size, saveSize, 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(int maxBitrate, Context context, String id) { - return musicService.getVideoUrl(maxBitrate, context, id); - } - - @Override - public String getVideoStreamUrl(String format, int maxBitrate, Context context, String id) throws Exception { - return musicService.getVideoStreamUrl(format, maxBitrate, context, id); - } - - @Override - public String getHlsUrl(String id, int bitRate, Context context) throws Exception { - return musicService.getHlsUrl(id, bitRate, context); - } - - @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); - } - - @Override - public void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception { - musicService.setStarred(id, starred, context, progressListener); - } - - @Override - public List<Share> getShares(Context context, ProgressListener progressListener) throws Exception { - return musicService.getShares(context, progressListener); - } - - @Override - public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception { - return musicService.getChatMessages(since, context, progressListener); - } - - @Override - public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception { - musicService.addChatMessage(message, context, progressListener); - } - - @Override - public List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - List<Genre> result = refresh ? null : cachedGenres.get(); - - if (result == null) { - result = musicService.getGenres(refresh, context, progressListener); - cachedGenres.set(result); - } - - return result; - } - - @Override - public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception { - return musicService.getSongsByGenre(genre, count, offset, context, progressListener); - } - - @Override - public List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - List<PodcastChannel> result = refresh ? null : cachedPodcastChannels.get(); - - if (result == null) { - result = musicService.getPodcastChannels(refresh, context, progressListener); - cachedPodcastChannels.set(result); - } - - return result; - } - - @Override - public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { - return musicService.getPodcastEpisodes(id, context, progressListener); - } - - @Override - public void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception { - musicService.refreshPodcasts(context, progressListener); - } - - @Override - public void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception{ - musicService.createPodcastChannel(url, context, progressListener); - } - - @Override - public void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception{ - musicService.deletePodcastChannel(id, context, progressListener); - } - - @Override - public void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - musicService.downloadPodcastEpisode(id, context, progressListener); - } - - @Override - public void deletePodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - musicService.deletePodcastEpisode(id, context, progressListener); - } - - @Override - public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ - return musicService.processOfflineSyncs(context, progressListener); - } - - - - private void checkSettingsChanged(Context context) { - String newUrl = Util.getRestUrl(context, null); - if (!Util.equals(newUrl, restUrl)) { - cachedMusicFolders.clear(); - cachedMusicDirectories.evictAll(); - cachedLicenseValid.clear(); - cachedIndexes.clear(); - cachedPlaylists.clear(); - cachedPodcastChannels.clear(); - restUrl = newUrl; - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/DownloadFile.java b/subsonic-android/src/github/daneren2005/dsub/service/DownloadFile.java deleted file mode 100644 index 5ab7ad70..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/DownloadFile.java +++ /dev/null @@ -1,398 +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 github.daneren2005.dsub.service; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import android.content.Context; -import android.net.wifi.WifiManager; -import android.os.PowerManager; -import android.util.DisplayMetrics; -import android.util.Log; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.CancellableTask; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.util.CacheCleaner; -import org.apache.http.Header; - -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; - private boolean isPlaying = false; - private boolean saveWhenDone = false; - private boolean completeWhenDone = false; - private Integer contentLength = null; - - public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) { - this.context = context; - this.song = song; - this.save = save; - saveFile = FileUtil.getSongFile(context, song); - bitRate = Util.getMaxBitrate(context); - partialFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) + - ".partial." + FileUtil.getExtension(saveFile.getName())); - completeFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) + - ".complete." + FileUtil.getExtension(saveFile.getName())); - mediaStoreService = new MediaStoreService(context); - } - - public MusicDirectory.Entry getSong() { - return song; - } - - /** - * Returns the effective bit rate. - */ - public int getBitRate() { - if(!partialFile.exists()) { - bitRate = Util.getMaxBitrate(context); - } - if (bitRate > 0) { - return bitRate; - } - return song.getBitRate() == null ? 160 : song.getBitRate(); - } - - public Integer getContentLength() { - return contentLength; - } - - public synchronized void download() { - FileUtil.createDirectoryForParent(saveFile); - failed = false; - if(!partialFile.exists()) { - bitRate = Util.getMaxBitrate(context); - } - downloadTask = new DownloadTask(); - downloadTask.start(); - } - - public synchronized void cancelDownload() { - if (downloadTask != null) { - downloadTask.cancel(); - } - } - - 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) || saveWhenDone || completeWhenDone; - } - - 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); - } - } - } - - public void setPlaying(boolean isPlaying) { - try { - if(saveWhenDone && isPlaying == false) { - Util.renameFile(completeFile, saveFile); - saveWhenDone = false; - } else if(completeWhenDone && isPlaying == false) { - if(save) { - Util.renameFile(partialFile, saveFile); - mediaStoreService.saveInMediaStore(DownloadFile.this); - } else { - Util.renameFile(partialFile, completeFile); - } - completeWhenDone = false; - } - } catch(IOException ex) { - Log.w(TAG, "Failed to rename file " + completeFile + " to " + saveFile); - } - - this.isPlaying = isPlaying; - } - public boolean getPlaying() { - return isPlaying; - } - - @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; - WifiManager.WifiLock wifiLock = null; - try { - - if (Util.isScreenLitOnDownload(context)) { - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, toString()); - wakeLock.acquire(); - Log.i(TAG, "Acquired wake lock " + wakeLock); - } - - wifiLock = Util.createWifiLock(context, toString()); - wifiLock.acquire(); - - if (saveFile.exists()) { - Log.i(TAG, saveFile + " already exists. Skipping."); - return; - } - if (completeFile.exists()) { - if (save) { - if(isPlaying) { - saveWhenDone = true; - } else { - Util.renameFile(completeFile, saveFile); - } - } else { - Log.i(TAG, completeFile + " already exists. Skipping."); - } - return; - } - - MusicService musicService = MusicServiceFactory.getMusicService(context); - - // Some devices seem to throw error on partial file which doesn't exist - boolean compare; - try { - compare = (bitRate == 0) || (song.getDuration() == 0) || (partialFile.length() == 0) || (bitRate * song.getDuration() * 1000 / 8) > partialFile.length(); - } catch(Exception e) { - compare = true; - } - if(compare) { - // Attempt partial HTTP GET, appending to the file if it exists. - HttpResponse response = musicService.getDownloadInputStream(context, song, partialFile.length(), bitRate, DownloadTask.this); - Header contentLengthHeader = response.getFirstHeader("Content-Length"); - if(contentLengthHeader != null) { - String contentLengthString = contentLengthHeader.getValue(); - if(contentLengthString != null) { - Log.i(TAG, "Content Length: " + contentLengthString); - contentLength = Integer.parseInt(contentLengthString); - } - } - 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(isPlaying) { - completeWhenDone = true; - } else { - if(save) { - Util.renameFile(partialFile, saveFile); - mediaStoreService.saveInMediaStore(DownloadFile.this); - } else { - Util.renameFile(partialFile, completeFile); - } - } - - } catch (Exception x) { - Util.close(out); - Util.delete(completeFile); - Util.delete(saveFile); - if (!isCancelled()) { - failed = true; - Log.w(TAG, "Failed to download '" + song + "'.", x); - } - - } finally { - Util.close(in); - Util.close(out); - if (wakeLock != null) { - wakeLock.release(); - Log.i(TAG, "Released wake lock " + wakeLock); - } - if (wifiLock != null) { - wifiLock.release(); - } - new CacheCleaner(context, DownloadServiceImpl.getInstance()).cleanSpace(); - if(DownloadServiceImpl.getInstance() != null) { - ((DownloadServiceImpl)DownloadServiceImpl.getInstance()).checkDownloads(); - } - } - } - - @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, size, 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/github/daneren2005/dsub/service/DownloadService.java b/subsonic-android/src/github/daneren2005/dsub/service/DownloadService.java deleted file mode 100644 index 328cc962..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/DownloadService.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 github.daneren2005.dsub.service; - -import java.util.List; - -import github.daneren2005.dsub.audiofx.EqualizerController; -import github.daneren2005.dsub.audiofx.VisualizerController; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.RepeatMode; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public interface DownloadService { - - void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle); - void downloadBackground(List<MusicDirectory.Entry> songs, boolean save); - - 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 clearBackground(); - - void clearIncomplete(); - - int size(); - - void remove(int which); - - void remove(DownloadFile downloadFile); - - List<DownloadFile> getSongs(); - - List<DownloadFile> getDownloads(); - - List<DownloadFile> getBackgroundDownloads(); - - int getCurrentPlayingIndex(); - - DownloadFile getCurrentPlaying(); - - DownloadFile getCurrentDownloading(); - - void play(int index); - - void seekTo(int position); - - void previous(); - - void next(); - - void pause(); - - void stop(); - - 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 id); - - String getSuggestedPlaylistName(); - - String getSuggestedPlaylistId(); - - boolean getEqualizerAvailable(); - - boolean getVisualizerAvailable(); - - EqualizerController getEqualizerController(); - - VisualizerController getVisualizerController(); - - boolean isJukeboxEnabled(); - - void setJukeboxEnabled(boolean b); - - void adjustJukeboxVolume(boolean up); - - void setSleepTimerDuration(int duration); - - void startSleepTimer(); - - void stopSleepTimer(); - - boolean getSleepTimer(); - - void setVolume(float volume); - - void swap(boolean mainList, int from, int to); -} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java b/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java deleted file mode 100644 index 04875f34..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java +++ /dev/null @@ -1,1539 +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 github.daneren2005.dsub.service; - -import static github.daneren2005.dsub.domain.PlayerState.COMPLETED; -import static github.daneren2005.dsub.domain.PlayerState.DOWNLOADING; -import static github.daneren2005.dsub.domain.PlayerState.IDLE; -import static github.daneren2005.dsub.domain.PlayerState.PAUSED; -import static github.daneren2005.dsub.domain.PlayerState.PREPARED; -import static github.daneren2005.dsub.domain.PlayerState.PREPARING; -import static github.daneren2005.dsub.domain.PlayerState.STARTED; -import static github.daneren2005.dsub.domain.PlayerState.STOPPED; -import github.daneren2005.dsub.audiofx.EqualizerController; -import github.daneren2005.dsub.audiofx.VisualizerController; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.RepeatMode; -import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; -import github.daneren2005.dsub.util.CancellableTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ShufflePlayBuffer; -import github.daneren2005.dsub.util.SimpleServiceBinder; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.util.compat.RemoteControlClientHelper; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -import android.app.Service; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.media.audiofx.AudioEffect; -import android.os.Build; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.PowerManager; -import android.util.Log; -import android.support.v4.util.LruCache; -import java.net.URLEncoder; - -/** - * @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 = "github.daneren2005.dsub.CMD_PLAY"; - public static final String CMD_TOGGLEPAUSE = "github.daneren2005.dsub.CMD_TOGGLEPAUSE"; - public static final String CMD_PAUSE = "github.daneren2005.dsub.CMD_PAUSE"; - public static final String CMD_STOP = "github.daneren2005.dsub.CMD_STOP"; - public static final String CMD_PREVIOUS = "github.daneren2005.dsub.CMD_PREVIOUS"; - public static final String CMD_NEXT = "github.daneren2005.dsub.CMD_NEXT"; - - - private RemoteControlClientHelper mRemoteControl; - - private final IBinder binder = new SimpleServiceBinder<DownloadService>(this); - private Looper mediaPlayerLooper; - private MediaPlayer mediaPlayer; - private MediaPlayer nextMediaPlayer; - private boolean nextSetup = false; - private boolean isPartial = true; - private final List<DownloadFile> downloadList = new ArrayList<DownloadFile>(); - private final List<DownloadFile> backgroundDownloadList = new ArrayList<DownloadFile>(); - private final Handler handler = new Handler(); - private Handler mediaPlayerHandler; - 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 nextPlaying; - private DownloadFile currentDownloading; - private CancellableTask bufferTask; - private CancellableTask nextPlayingTask; - private PlayerState playerState = IDLE; - private PlayerState nextPlayerState = IDLE; - private boolean shufflePlay; - private long revision; - private static DownloadService instance; - private String suggestedPlaylistName; - private String suggestedPlaylistId; - private PowerManager.WakeLock wakeLock; - private boolean keepScreenOn; - private int cachedPosition = 0; - - private static boolean equalizerAvailable; - private static boolean visualizerAvailable; - private EqualizerController equalizerController; - private VisualizerController visualizerController; - private boolean showVisualization; - private boolean jukeboxEnabled; - private PositionCache positionCache; - private StreamProxy proxy; - - private Timer sleepTimer; - private int timerDuration; - private boolean autoPlayStart = false; - - static { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { - equalizerAvailable = true; - visualizerAvailable = true; - } - } - - @Override - public void onCreate() { - super.onCreate(); - - new Thread(new Runnable() { - public void run() { - Looper.prepare(); - - mediaPlayer = new MediaPlayer(); - mediaPlayer.setWakeMode(DownloadServiceImpl.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; - } - }); - - try { - Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION); - i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mediaPlayer.getAudioSessionId()); - i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); - sendBroadcast(i); - } catch(Throwable e) { - // Froyo or lower - } - - mediaPlayerLooper = Looper.myLooper(); - mediaPlayerHandler = new Handler(mediaPlayerLooper); - Looper.loop(); - } - }).start(); - - Util.registerMediaButtonEventReceiver(this); - - if (mRemoteControl == null) { - // Use the remote control APIs (if available) to set the playback state - mRemoteControl = RemoteControlClientHelper.createInstance(); - ComponentName mediaButtonReceiverComponent = new ComponentName(getPackageName(), MediaButtonIntentReceiver.class.getName()); - mRemoteControl.register(this, mediaButtonReceiverComponent); - } - - PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); - wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); - wakeLock.setReferenceCounted(false); - - SharedPreferences prefs = Util.getPreferences(this); - try { - timerDuration = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, "5")); - } catch(Throwable e) { - timerDuration = 5; - } - sleepTimer = null; - - keepScreenOn = prefs.getBoolean(Constants.PREFERENCES_KEY_KEEP_SCREEN_ON, false); - - instance = this; - lifecycleSupport.onCreate(); - - if(prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false)) { - getEqualizerController(); - } - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - super.onStartCommand(intent, flags, startId); - lifecycleSupport.onStart(intent); - return START_NOT_STICKY; - } - - @Override - public void onDestroy() { - super.onDestroy(); - instance = null; - - if(currentPlaying != null) currentPlaying.setPlaying(false); - if(sleepTimer != null){ - sleepTimer.cancel(); - sleepTimer.purge(); - } - lifecycleSupport.onDestroy(); - - try { - Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); - i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mediaPlayer.getAudioSessionId()); - i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); - sendBroadcast(i); - } catch(Throwable e) { - // Froyo or lower - } - - mediaPlayer.release(); - if(nextMediaPlayer != null) { - nextMediaPlayer.release(); - } - mediaPlayerLooper.quit(); - shufflePlayBuffer.shutdown(); - if (equalizerController != null) { - equalizerController.release(); - } - if (visualizerController != null) { - visualizerController.release(); - } - if (mRemoteControl != null) { - mRemoteControl.unregister(this); - mRemoteControl = null; - } - - if(bufferTask != null) { - bufferTask.cancel(); - } - if(nextPlayingTask != null) { - nextPlayingTask.cancel(); - } - Util.hidePlayingNotification(this, this, handler); - } - - 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, boolean shuffle) { - setShufflePlayEnabled(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 { - int size = size(); - int index = getCurrentPlayingIndex(); - for (MusicDirectory.Entry song : songs) { - DownloadFile downloadFile = new DownloadFile(this, song, save); - downloadList.add(downloadFile); - } - if(!autoplay && (size - 1) == index) { - setNextPlaying(); - } - revision++; - } - updateJukeboxPlaylist(); - - if(shuffle) { - shuffle(); - } - - if (autoplay) { - play(0); - } else { - if (currentPlaying == null) { - currentPlaying = downloadList.get(0); - currentPlaying.setPlaying(true); - } - checkDownloads(); - } - lifecycleSupport.serializeDownloadQueue(); - } - public synchronized void downloadBackground(List<MusicDirectory.Entry> songs, boolean save) { - for (MusicDirectory.Entry song : songs) { - DownloadFile downloadFile = new DownloadFile(this, song, save); - backgroundDownloadList.add(downloadFile); - } - revision++; - - checkDownloads(); - lifecycleSupport.serializeDownloadQueue(); - } - - private void updateJukeboxPlaylist() { - if (jukeboxEnabled) { - jukeboxService.updatePlaylist(); - } - } - - public void restore(List<MusicDirectory.Entry> songs, int currentPlayingIndex, int currentPlayingPosition) { - SharedPreferences prefs = Util.getPreferences(this); - boolean startShufflePlay = prefs.getBoolean(Constants.PREFERENCES_KEY_SHUFFLE_MODE, false); - download(songs, false, false, false, false); - if(startShufflePlay) { - shufflePlay = true; - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_SHUFFLE_MODE, true); - editor.commit(); - } - if (currentPlayingIndex != -1) { - while(mediaPlayer == null) { - Util.sleepQuietly(50L); - } - - play(currentPlayingIndex, false); - if (currentPlaying != null && currentPlaying.isCompleteFileAvailable()) { - doPlay(currentPlaying, currentPlayingPosition, autoPlayStart); - } - autoPlayStart = false; - } - } - - @Override - public synchronized void setShufflePlayEnabled(boolean enabled) { - shufflePlay = enabled; - if (shufflePlay) { - clear(); - checkDownloads(); - } - SharedPreferences.Editor editor = Util.getPreferences(this).edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_SHUFFLE_MODE, enabled); - editor.commit(); - } - - @Override - public 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(); - setNextPlaying(); - } - - @Override - public RepeatMode getRepeatMode() { - return Util.getRepeatMode(this); - } - - @Override - public void setRepeatMode(RepeatMode repeatMode) { - Util.setRepeatMode(this, repeatMode); - setNextPlaying(); - } - - @Override - public boolean getKeepScreenOn() { - return keepScreenOn; - } - - @Override - public void setKeepScreenOn(boolean keepScreenOn) { - this.keepScreenOn = keepScreenOn; - - SharedPreferences prefs = Util.getPreferences(this); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_KEEP_SCREEN_ON, keepScreenOn); - editor.commit(); - } - - @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) && - ((downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && downloadFile.getPartialFile().exists()) - || downloadFile.isWorkDone())) { - return downloadFile; - } - } - for (DownloadFile downloadFile : backgroundDownloadList) { - 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 clearBackground() { - if(currentDownloading != null && backgroundDownloadList.contains(currentDownloading)) { - currentDownloading.cancelDownload(); - currentDownloading = null; - } - backgroundDownloadList.clear(); - } - - @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(); - setNextPlaying(); - } - - @Override - public synchronized void remove(int which) { - downloadList.remove(which); - } - - @Override - public synchronized void remove(DownloadFile downloadFile) { - if (downloadFile == currentDownloading) { - currentDownloading.cancelDownload(); - currentDownloading = null; - } - if (downloadFile == currentPlaying) { - reset(); - setCurrentPlaying(null, false); - } - downloadList.remove(downloadFile); - backgroundDownloadList.remove(downloadFile); - revision++; - lifecycleSupport.serializeDownloadQueue(); - updateJukeboxPlaylist(); - if(downloadFile == nextPlaying) { - setNextPlaying(); - } - } - - @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) { - if(this.currentPlaying != null) { - this.currentPlaying.setPlaying(false); - } - this.currentPlaying = currentPlaying; - - if (currentPlaying != null) { - Util.broadcastNewTrackInfo(this, currentPlaying.getSong()); - mRemoteControl.updateMetadata(this, currentPlaying.getSong()); - } else { - Util.broadcastNewTrackInfo(this, null); - Util.hidePlayingNotification(this, this, handler); - } - } - - synchronized void setNextPlaying() { - SharedPreferences prefs = Util.getPreferences(DownloadServiceImpl.this); - boolean gaplessPlayback = prefs.getBoolean(Constants.PREFERENCES_KEY_GAPLESS_PLAYBACK, true); - if(!gaplessPlayback) { - nextPlaying = null; - nextPlayerState = IDLE; - return; - } - - int index = getCurrentPlayingIndex(); - if (index != -1) { - switch (getRepeatMode()) { - case OFF: - index = index + 1; - break; - case ALL: - index = (index + 1) % size(); - break; - case SINGLE: - break; - default: - break; - } - } - - nextSetup = false; - if(nextPlayingTask != null) { - nextPlayingTask.cancel(); - nextPlayingTask = null; - } - if(index < size() && index != -1) { - nextPlaying = downloadList.get(index); - nextPlayingTask = new CheckCompletionTask(nextPlaying); - nextPlayingTask.start(); - } else { - nextPlaying = null; - setNextPlayerState(IDLE); - } - } - - @Override - public synchronized int getCurrentPlayingIndex() { - return downloadList.indexOf(currentPlaying); - } - - @Override - public DownloadFile getCurrentPlaying() { - return currentPlaying; - } - - @Override - public DownloadFile getCurrentDownloading() { - return currentDownloading; - } - - @Override - public List<DownloadFile> getSongs() { - return downloadList; - } - - @Override - public synchronized List<DownloadFile> getDownloads() { - List<DownloadFile> temp = new ArrayList<DownloadFile>(); - temp.addAll(downloadList); - temp.addAll(backgroundDownloadList); - return temp; - } - - @Override - public List<DownloadFile> getBackgroundDownloads() { - return backgroundDownloadList; - } - - /** 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); - lifecycleSupport.serializeDownloadQueue(); - } else { - if(nextPlayingTask != null) { - nextPlayingTask.cancel(); - nextPlayingTask = null; - } - setCurrentPlaying(index, start); - if (start) { - if (jukeboxEnabled) { - jukeboxService.skip(getCurrentPlayingIndex(), 0); - setPlayerState(STARTED); - } else { - bufferAndPlay(); - } - } - checkDownloads(); - setNextPlaying(); - } - } - private synchronized void playNext() { - if(nextPlaying != null && nextPlayerState == PlayerState.PREPARED) { - if(!nextSetup) { - playNext(true); - } else { - nextSetup = false; - playNext(false); - } - } else { - onSongCompleted(); - } - } - private synchronized void playNext(boolean start) { - // Swap the media players since nextMediaPlayer is ready to play - if(start) { - nextMediaPlayer.start(); - } else { - Log.i(TAG, "nextMediaPlayer already playing"); - } - MediaPlayer tmp = mediaPlayer; - mediaPlayer = nextMediaPlayer; - nextMediaPlayer = tmp; - setCurrentPlaying(nextPlaying, true); - setPlayerState(PlayerState.STARTED); - setupHandlers(currentPlaying, false); - setNextPlaying(); - - // Proxy should not be being used here since the next player was already setup to play - if(proxy != null) { - proxy.stop(); - proxy = null; - } - } - - /** Plays or resumes the playback, depending on the current player state. */ - public synchronized void togglePlayPause() { - if (playerState == PAUSED || playerState == COMPLETED || playerState == STOPPED) { - start(); - } else if (playerState == STOPPED || playerState == IDLE) { - autoPlayStart = true; - 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); - cachedPosition = 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 stop() { - try { - if (playerState == STARTED) { - if (jukeboxEnabled) { - jukeboxService.stop(); - } else { - mediaPlayer.pause(); - } - setPlayerState(STOPPED); - } else if(playerState == PAUSED) { - setPlayerState(STOPPED); - } - } 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 { - setPlayerState(IDLE); - mediaPlayer.setOnErrorListener(null); - mediaPlayer.setOnCompletionListener(null); - mediaPlayer.reset(); - } 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 cachedPosition; - } - } 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; - } - - public synchronized void setPlayerState(final PlayerState playerState) { - Log.i(TAG, this.playerState.name() + " -> " + playerState.name() + " (" + currentPlaying + ")"); - - if (playerState == PAUSED) { - lifecycleSupport.serializeDownloadQueue(); - } - - boolean show = playerState == PlayerState.STARTED; - boolean pause = playerState == PlayerState.PAUSED; - boolean hide = playerState == PlayerState.STOPPED; - Util.broadcastPlaybackStatusChange(this, playerState); - - this.playerState = playerState; - - if(playerState == STARTED) { - Util.requestAudioFocus(this); - } - - if (show) { - Util.showPlayingNotification(this, this, handler, currentPlaying.getSong()); - } else if (pause) { - SharedPreferences prefs = Util.getPreferences(this); - if(prefs.getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false)) { - Util.showPlayingNotification(this, this, handler, currentPlaying.getSong()); - } else { - Util.hidePlayingNotification(this, this, handler); - } - } else if(hide) { - Util.hidePlayingNotification(this, this, handler); - } - mRemoteControl.setPlaybackState(playerState.getRemoteControlClientPlayState()); - - if (playerState == STARTED) { - scrobbler.scrobble(this, currentPlaying, false); - } else if (playerState == COMPLETED) { - scrobbler.scrobble(this, currentPlaying, true); - } - - if(playerState == STARTED && positionCache == null) { - positionCache = new PositionCache(); - Thread thread = new Thread(positionCache); - thread.start(); - } else if(playerState != STARTED && positionCache != null) { - positionCache.stop(); - positionCache = null; - } - } - - private class PositionCache implements Runnable { - boolean isRunning = true; - - public void stop() { - isRunning = false; - } - - @Override - public void run() { - // Stop checking position before the song reaches completion - while(isRunning) { - try { - if(mediaPlayer != null && playerState == STARTED) { - cachedPosition = mediaPlayer.getCurrentPosition(); - } - Thread.sleep(200L); - } - catch(Exception e) { - Log.w(TAG, "Crashed getting current position", e); - isRunning = false; - positionCache = null; - } - } - } - } - - private void setPlayerStateCompleted() { - Log.i(TAG, this.playerState.name() + " -> " + PlayerState.COMPLETED + " (" + currentPlaying + ")"); - this.playerState = PlayerState.COMPLETED; - if(positionCache != null) { - positionCache.stop(); - positionCache = null; - } - scrobbler.scrobble(this, currentPlaying, true); - } - - private synchronized void setNextPlayerState(PlayerState playerState) { - Log.i(TAG, "Next: " + this.nextPlayerState.name() + " -> " + playerState.name() + " (" + nextPlaying + ")"); - this.nextPlayerState = playerState; - } - - @Override - public void setSuggestedPlaylistName(String name, String id) { - this.suggestedPlaylistName = name; - this.suggestedPlaylistId = id; - } - - @Override - public String getSuggestedPlaylistName() { - return suggestedPlaylistName; - } - - @Override - public String getSuggestedPlaylistId() { - return suggestedPlaylistId; - } - - @Override - public boolean getEqualizerAvailable() { - return equalizerAvailable; - } - - @Override - public boolean getVisualizerAvailable() { - return visualizerAvailable; - } - - @Override - public EqualizerController getEqualizerController() { - if (equalizerAvailable && equalizerController == null) { - equalizerController = new EqualizerController(this, mediaPlayer); - if (!equalizerController.isAvailable()) { - equalizerController = null; - } else { - equalizerController.loadSettings(); - } - } - return equalizerController; - } - - @Override - public VisualizerController getVisualizerController() { - if (visualizerAvailable && visualizerController == null) { - visualizerController = new VisualizerController(this, mediaPlayer); - if (!visualizerController.isAvailable()) { - visualizerController = null; - } - } - 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() { - if(playerState != PREPARED) { - reset(); - - bufferTask = new BufferTask(currentPlaying, 0); - bufferTask.start(); - } else { - doPlay(currentPlaying, 0, true); - } - } - - private synchronized void doPlay(final DownloadFile downloadFile, final int position, final boolean start) { - try { - downloadFile.setPlaying(true); - final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); - isPartial = file.equals(downloadFile.getPartialFile()); - downloadFile.updateModificationDate(); - - mediaPlayer.setOnCompletionListener(null); - mediaPlayer.reset(); - setPlayerState(IDLE); - mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - String dataSource = file.getPath(); - if(isPartial) { - if (proxy == null) { - proxy = new StreamProxy(this); - proxy.start(); - } - dataSource = String.format("http://127.0.0.1:%d/%s", proxy.getPort(), URLEncoder.encode(dataSource, Constants.UTF_8)); - Log.i(TAG, "Data Source: " + dataSource); - } else if(proxy != null) { - proxy.stop(); - proxy = null; - } - mediaPlayer.setDataSource(dataSource); - setPlayerState(PREPARING); - - mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() { - public void onBufferingUpdate(MediaPlayer mp, int percent) { - Log.i(TAG, "Buffered " + percent + "%"); - if(percent == 100) { - mediaPlayer.setOnBufferingUpdateListener(null); - } - } - }); - - mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { - public void onPrepared(MediaPlayer mediaPlayer) { - try { - setPlayerState(PREPARED); - - synchronized (DownloadServiceImpl.this) { - if (position != 0) { - Log.i(TAG, "Restarting player from position " + position); - mediaPlayer.seekTo(position); - } - cachedPosition = position; - - if (start) { - mediaPlayer.start(); - setPlayerState(STARTED); - } else { - setPlayerState(PAUSED); - } - } - - lifecycleSupport.serializeDownloadQueue(); - } catch (Exception x) { - handleError(x); - } - } - }); - - setupHandlers(downloadFile, isPartial); - - mediaPlayer.prepareAsync(); - } catch (Exception x) { - handleError(x); - } - } - - private synchronized void setupNext(final DownloadFile downloadFile) { - try { - final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); - if(nextMediaPlayer != null) { - nextMediaPlayer.setOnCompletionListener(null); - nextMediaPlayer.release(); - nextMediaPlayer = null; - } - nextMediaPlayer = new MediaPlayer(); - nextMediaPlayer.setWakeMode(DownloadServiceImpl.this, PowerManager.PARTIAL_WAKE_LOCK); - try { - nextMediaPlayer.setAudioSessionId(mediaPlayer.getAudioSessionId()); - } catch(Throwable e) { - nextMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - } - nextMediaPlayer.setDataSource(file.getPath()); - setNextPlayerState(PREPARING); - - nextMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { - public void onPrepared(MediaPlayer mp) { - try { - setNextPlayerState(PREPARED); - - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED)) { - mediaPlayer.setNextMediaPlayer(nextMediaPlayer); - nextSetup = true; - } - } catch (Exception x) { - handleErrorNext(x); - } - } - }); - - nextMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { - public boolean onError(MediaPlayer mediaPlayer, int what, int extra) { - Log.w(TAG, "Error on playing next " + "(" + what + ", " + extra + "): " + downloadFile); - return true; - } - }); - - nextMediaPlayer.prepareAsync(); - } catch (Exception x) { - handleErrorNext(x); - } - } - - private void setupHandlers(final DownloadFile downloadFile, final boolean isPartial) { - final int duration = downloadFile.getSong().getDuration() == null ? 0 : downloadFile.getSong().getDuration() * 1000; - mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { - public boolean onError(MediaPlayer mediaPlayer, int what, int extra) { - Log.w(TAG, "Error on playing file " + "(" + what + ", " + extra + "): " + downloadFile); - int pos = cachedPosition; - reset(); - if (!isPartial || (downloadFile.isWorkDone() && (Math.abs(duration - pos) < 10000))) { - playNext(); - } else { - downloadFile.setPlaying(false); - doPlay(downloadFile, pos, true); - downloadFile.setPlaying(true); - } - return true; - } - }); - - 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); - - setPlayerStateCompleted(); - - int pos = cachedPosition; - Log.i(TAG, "Ending position " + pos + " of " + duration); - if (!isPartial || (downloadFile.isWorkDone() && (Math.abs(duration - pos) < 10000))) { - playNext(); - return; - } - - // If file is not completely downloaded, restart the playback from the current position. - synchronized (DownloadServiceImpl.this) { - if(downloadFile.isWorkDone()) { - // Complete was called early even though file is fully buffered - Log.i(TAG, "Requesting restart from " + pos + " of " + duration); - reset(); - downloadFile.setPlaying(false); - doPlay(downloadFile, pos, true); - downloadFile.setPlaying(true); - } else { - Log.i(TAG, "Requesting restart from " + pos + " of " + duration); - reset(); - bufferTask = new BufferTask(downloadFile, pos); - bufferTask.start(); - } - } - } - }); - } - - @Override - public void setSleepTimerDuration(int duration){ - timerDuration = duration; - } - - @Override - public void startSleepTimer(){ - if(sleepTimer != null){ - sleepTimer.cancel(); - sleepTimer.purge(); - } - - sleepTimer = new Timer(); - - sleepTimer.schedule(new TimerTask() { - @Override - public void run() { - pause(); - sleepTimer.cancel(); - sleepTimer.purge(); - sleepTimer = null; - } - - }, timerDuration * 60 * 1000); - } - - @Override - public void stopSleepTimer() { - if(sleepTimer != null){ - sleepTimer.cancel(); - sleepTimer.purge(); - } - sleepTimer = null; - } - - @Override - public boolean getSleepTimer() { - return sleepTimer != null; - } - - @Override - public void setVolume(float volume) { - if(mediaPlayer != null) { - mediaPlayer.setVolume(volume, volume); - } - } - - @Override - public synchronized void swap(boolean mainList, int from, int to) { - List<DownloadFile> list = mainList ? downloadList : backgroundDownloadList; - int max = list.size(); - if(to >= max) { - to = max - 1; - } - else if(to < 0) { - to = 0; - } - - int currentPlayingIndex = getCurrentPlayingIndex(); - DownloadFile movedSong = list.remove(from); - list.add(to, movedSong); - if(jukeboxEnabled && mainList) { - updateJukeboxPlaylist(); - } else if(mainList && (movedSong == nextPlaying || (currentPlayingIndex + 1) == to)) { - // Moving next playing or moving a song to be next playing - setNextPlaying(); - } - } - - private void handleError(Exception x) { - Log.w(TAG, "Media player error: " + x, x); - mediaPlayer.reset(); - setPlayerState(IDLE); - } - private void handleErrorNext(Exception x) { - Log.w(TAG, "Next Media player error: " + x, x); - nextMediaPlayer.reset(); - setNextPlayerState(IDLE); - } - - protected synchronized void checkDownloads() { - if (!Util.isExternalStoragePresent() || !lifecycleSupport.isExternalStorageAvailable()) { - return; - } - - if (shufflePlay) { - checkShufflePlay(); - } - - if (jukeboxEnabled || !Util.isNetworkConnected(this)) { - return; - } - - if (downloadList.isEmpty() && backgroundDownloadList.isEmpty()) { - return; - } - - // Need to download current playing? - if (currentPlaying != null && currentPlaying != currentDownloading && !currentPlaying.isWorkDone()) { - // 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() && (!downloadList.isEmpty() || !backgroundDownloadList.isEmpty())) { - currentDownloading = null; - int n = size(); - - int preloaded = 0; - - if(n != 0) { - int start = currentPlaying == null ? 0 : getCurrentPlayingIndex(); - if(start == -1) { - start = 0; - } - 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); - if(i == (start + 1)) { - setNextPlayerState(DOWNLOADING); - } - break; - } - } else if (currentPlaying != downloadFile) { - preloaded++; - } - - i = (i + 1) % n; - } while (i != start); - } - - if((preloaded + 1 == n || preloaded >= Util.getPreloadCount(this) || downloadList.isEmpty()) && !backgroundDownloadList.isEmpty()) { - for(int i = 0; i < backgroundDownloadList.size(); i++) { - DownloadFile downloadFile = backgroundDownloadList.get(i); - if(downloadFile.isWorkDone() && (!downloadFile.shouldSave() || downloadFile.isSaved())) { - // Don't need to keep list like active song list - backgroundDownloadList.remove(i); - revision++; - i--; - } else { - currentDownloading = downloadFile; - currentDownloading.download(); - cleanupCandidates.add(currentDownloading); - break; - } - } - } - } - - // Delete obsolete .partial and .complete files. - cleanup(); - } - - private synchronized void checkShufflePlay() { - - // Get users desired random playlist size - SharedPreferences prefs = Util.getPreferences(this); - int listSize = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_RANDOM_SIZE, "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 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(); - - SharedPreferences prefs = Util.getPreferences(DownloadServiceImpl.this); - long bufferLength = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_BUFFER_LENGTH, "5")); - if(bufferLength == 0) { - // Set to seconds in a day, basically infinity - bufferLength = 86400L; - } - - // Calculate roughly how many bytes BUFFER_LENGTH_SECONDS corresponds to. - int bitRate = downloadFile.getBitRate(); - long byteCount = Math.max(100000, bitRate * 1024L / 8L * bufferLength); - - // Find out how large the file should grow before resuming playback. - Log.i(TAG, "Buffering from position " + position + " and bitrate " + bitRate); - expectedFileSize = (position * bitRate / 8) + 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.isWorkDone(); - long size = partialFile.length(); - - Log.i(TAG, "Buffering " + partialFile + " (" + size + "/" + expectedFileSize + ", " + completeFileAvailable + ")"); - return completeFileAvailable || size >= expectedFileSize; - } - - @Override - public String toString() { - return "BufferTask (" + downloadFile + ")"; - } - } - - private class CheckCompletionTask extends CancellableTask { - private final DownloadFile downloadFile; - private final File partialFile; - - public CheckCompletionTask(DownloadFile downloadFile) { - setNextPlayerState(PlayerState.IDLE); - this.downloadFile = downloadFile; - if(downloadFile != null) { - partialFile = downloadFile.getPartialFile(); - } else { - partialFile = null; - } - } - - @Override - public void execute() { - if(downloadFile == null) { - return; - } - - // Do an initial sleep so this prepare can't compete with main prepare - Util.sleepQuietly(5000L); - while (!bufferComplete()) { - Util.sleepQuietly(5000L); - if (isCancelled()) { - return; - } - } - - // Start the setup of the next media player - mediaPlayerHandler.post(new Runnable() { - public void run() { - setupNext(downloadFile); - } - }); - } - - private boolean bufferComplete() { - boolean completeFileAvailable = downloadFile.isWorkDone(); - Log.i(TAG, "Buffering next " + partialFile + " (" + partialFile.length() + ")"); - return completeFileAvailable && (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED); - } - - @Override - public String toString() { - return "CheckCompletionTask (" + downloadFile + ")"; - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java b/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java deleted file mode 100644 index ae378865..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java +++ /dev/null @@ -1,352 +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 github.daneren2005.dsub.service; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.atomic.AtomicBoolean; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.media.RemoteControlClient; -import android.os.AsyncTask; -import android.os.Build; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; -import android.util.Log; -import android.view.KeyEvent; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.util.CacheCleaner; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.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; - private ReentrantLock lock = new ReentrantLock(); - private final AtomicBoolean setup = new AtomicBoolean(false); - private long lastPressTime = 0; - - /** - * This receiver manages the intent that could come from other applications. - */ - private BroadcastReceiver intentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - Log.i(TAG, "intentReceiver.onReceive: " + action); - if (DownloadServiceImpl.CMD_PLAY.equals(action)) { - downloadService.play(); - } else if (DownloadServiceImpl.CMD_NEXT.equals(action)) { - downloadService.next(); - } else if (DownloadServiceImpl.CMD_PREVIOUS.equals(action)) { - downloadService.previous(); - } else if (DownloadServiceImpl.CMD_TOGGLEPAUSE.equals(action)) { - downloadService.togglePlayPause(); - } else if (DownloadServiceImpl.CMD_PAUSE.equals(action)) { - downloadService.pause(); - } else if (DownloadServiceImpl.CMD_STOP.equals(action)) { - downloadService.pause(); - downloadService.seekTo(0); - } - } - }; - - - public DownloadServiceLifecycleSupport(DownloadServiceImpl downloadService) { - this.downloadService = downloadService; - } - - public void onCreate() { - Runnable downloadChecker = new Runnable() { - @Override - public void run() { - try { - downloadService.checkDownloads(); - } catch (Throwable x) { - Log.e(TAG, "checkDownloads() failed.", x); - } - } - }; - - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(downloadChecker, 5, 5, TimeUnit.SECONDS); - - // Pause when headset is unplugged. - headsetEventReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - Log.i(TAG, "Headset event for: " + intent.getExtras().get("name")); - if (intent.getExtras().getInt("state") == 0) { - if(!downloadService.isJukeboxEnabled()) { - 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(); - serializeDownloadQueueNow(); - 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() { - if(!setup.get()) { - return; - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - new SerializeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - new SerializeTask().execute(); - } - } - - public void serializeDownloadQueueNow() { - List<DownloadFile> songs = new ArrayList<DownloadFile>(downloadService.getSongs()); - State state = new State(); - for (DownloadFile downloadFile : songs) { - 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() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - new DeserializeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - new DeserializeTask().execute(); - } - } - private void deserializeDownloadQueueNow() { - State state = FileUtil.deserialize(downloadService, FILENAME_DOWNLOADS_SER); - if (state == null) { - return; - } - Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition); - downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition); - - // 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) { - switch (event.getKeyCode()) { - case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - downloadService.seekTo(downloadService.getPlayerPosition() - 10000); - break; - case RemoteControlClient.FLAG_KEY_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_NEXT: - downloadService.seekTo(downloadService.getPlayerPosition() + 10000); - break; - } - } else if(event.getAction() == KeyEvent.ACTION_UP) { - switch (event.getKeyCode()) { - case RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE: - downloadService.togglePlayPause(); - break; - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_HEADSETHOOK: - if(lastPressTime < (System.currentTimeMillis() - 500)) { - lastPressTime = System.currentTimeMillis(); - downloadService.togglePlayPause(); - } else { - downloadService.next(); - } - break; - case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - downloadService.previous(); - break; - case RemoteControlClient.FLAG_KEY_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_NEXT: - if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1) { - downloadService.next(); - } - break; - case RemoteControlClient.FLAG_KEY_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_STOP: - downloadService.stop(); - break; - case RemoteControlClient.FLAG_KEY_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PLAY: - if(downloadService.getPlayerState() != PlayerState.STARTED) { - downloadService.start(); - } - break; - case RemoteControlClient.FLAG_KEY_MEDIA_PAUSE: - 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 && !downloadService.isJukeboxEnabled()) { - resumeAfterCall = true; - downloadService.pause(); - } - break; - case TelephonyManager.CALL_STATE_IDLE: - if (resumeAfterCall) { - resumeAfterCall = false; - downloadService.start(); - } - break; - default: - break; - } - } - } - - private static class State implements Serializable { - private static final long serialVersionUID = -6346438781062572270L; - - private List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(); - private int currentPlayingIndex; - private int currentPlayingPosition; - } - - private class SerializeTask extends AsyncTask<Void, Void, Void> { - @Override - protected Void doInBackground(Void... params) { - if(lock.tryLock()) { - try { - serializeDownloadQueueNow(); - } finally { - lock.unlock(); - } - } - return null; - } - } - private class DeserializeTask extends AsyncTask<Void, Void, Void> { - @Override - protected Void doInBackground(Void... params) { - try { - lock.lock(); - deserializeDownloadQueueNow(); - setup.set(true); - } finally { - lock.unlock(); - } - return null; - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/JukeboxService.java b/subsonic-android/src/github/daneren2005/dsub/service/JukeboxService.java deleted file mode 100644 index 96b82336..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/JukeboxService.java +++ /dev/null @@ -1,358 +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 github.daneren2005.dsub.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 github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.JukeboxStatus; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.service.parser.SubsonicRESTException; -import github.daneren2005.dsub.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.setPlayerState(PlayerState.COMPLETED); - downloadService.setCurrentPlaying(index, true); - downloadService.setPlayerState(PlayerState.STARTED); - } - } - - 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/github/daneren2005/dsub/service/MediaStoreService.java b/subsonic-android/src/github/daneren2005/dsub/service/MediaStoreService.java deleted file mode 100644 index 4de77bf2..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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 github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/MusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java deleted file mode 100644 index 7aa878ab..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java +++ /dev/null @@ -1,140 +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 github.daneren2005.dsub.service; - -import java.util.List; - -import org.apache.http.HttpResponse; - -import android.content.Context; -import android.graphics.Bitmap; -import github.daneren2005.dsub.domain.ChatMessage; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.JukeboxStatus; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.domain.SearchCritera; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.domain.Version; -import github.daneren2005.dsub.util.CancellableTask; -import github.daneren2005.dsub.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, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getStarredList(Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception; - - List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception; - - void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception; - - void addToPlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception; - - void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception; - - void overwritePlaylist(String id, String name, int toRemove, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception; - - void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception; - - Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception; - - void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception; - - Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, int saveSize, 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(int maxBitrate, Context context, String id); - - String getVideoStreamUrl(String format, int Bitrate, Context context, String id) throws Exception; - - String getHlsUrl(String id, int bitRate, Context context) throws Exception; - - JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception; - - JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception; - - JukeboxStatus 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; - - void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception; - - List<Share> getShares(Context context, ProgressListener progressListener) throws Exception; - - List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception; - - void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception; - - List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception; - - List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception; - - void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception; - - void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception; - - void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception; - - void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception; - - void deletePodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception; - - int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception; -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/service/MusicServiceFactory.java b/subsonic-android/src/github/daneren2005/dsub/service/MusicServiceFactory.java deleted file mode 100644 index e04522ff..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service; - -import android.content.Context; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/OfflineException.java b/subsonic-android/src/github/daneren2005/dsub/service/OfflineException.java deleted file mode 100644 index e3a8d460..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/service/OfflineMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java deleted file mode 100644 index 22fdcd9b..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ /dev/null @@ -1,676 +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 github.daneren2005.dsub.service; - -import java.io.File; -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.content.SharedPreferences; -import android.graphics.Bitmap; -import android.media.MediaMetadataRetriever; -import android.util.Log; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.JukeboxStatus; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.domain.SearchCritera; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; -import java.io.*; -import java.util.Comparator; -import java.util.SortedSet; - -/** - * @author Sindre Mehus - */ -public class OfflineMusicService extends RESTMusicService { - private static final String TAG = OfflineMusicService.class.getSimpleName(); - - @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); - } - } - - SharedPreferences prefs = Util.getPreferences(context); - String ignoredArticlesString = prefs.getString(Constants.CACHE_KEY_IGNORE, "The El La Los Las Le Les"); - final String[] ignoredArticles = ignoredArticlesString.split(" "); - - Collections.sort(artists, new Comparator<Artist>() { - public int compare(Artist lhsArtist, Artist rhsArtist) { - String lhs = lhsArtist.getName().toLowerCase(); - String rhs = rhsArtist.getName().toLowerCase(); - - char lhs1 = lhs.charAt(0); - char rhs1 = rhs.charAt(0); - - if(Character.isDigit(lhs1) && !Character.isDigit(rhs1)) { - return 1; - } else if(Character.isDigit(rhs1) && !Character.isDigit(lhs1)) { - return -1; - } - - for(String article: ignoredArticles) { - int index = lhs.indexOf(article.toLowerCase() + " "); - if(index == 0) { - lhs = lhs.substring(article.length() + 1); - } - index = rhs.indexOf(article.toLowerCase() + " "); - if(index == 0) { - rhs = rhs.substring(article.length() + 1); - } - } - - return lhs.compareTo(rhs); - } - }); - - return new Indexes(0L, Collections.<Artist>emptyList(), artists); - } - - @Override - public MusicDirectory getMusicDirectory(String id, String artistName, 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.listMediaFiles(dir)) { - String name = getName(file); - if (name != null & !names.contains(name)) { - names.add(name); - result.addChild(createEntry(context, file, name)); - } - } - result.sortChildren(); - 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(); - if(!file.getParentFile().getParentFile().getPath().equals(root)) { - entry.setGrandParent(file.getParentFile().getParent()); - } - entry.setPath(file.getPath().replaceFirst("^" + root + "/" , "")); - String title = name; - if (file.isFile()) { - File artistFolder = file.getParentFile().getParentFile(); - File albumFolder = file.getParentFile(); - if(artistFolder.getPath().equals(root)) { - entry.setArtist(albumFolder.getName()); - } else { - entry.setArtist(artistFolder.getName()); - } - entry.setAlbum(albumFolder.getName()); - - int index = name.indexOf('-'); - if(index != -1) { - try { - entry.setTrack(Integer.parseInt(name.substring(0, index))); - title = title.substring(index + 1); - } catch(Exception e) { - // Failed parseInt, just means track filled out - } - } - - try { - MediaMetadataRetriever metadata = new MediaMetadataRetriever(); - metadata.setDataSource(file.getAbsolutePath()); - String discNumber = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER); - if(discNumber == null) { - discNumber = "1/1"; - } - int slashIndex = discNumber.indexOf("/"); - if(slashIndex > 0) { - discNumber = discNumber.substring(0, slashIndex); - } - entry.setDiscNumber(Integer.parseInt(discNumber)); - String bitrate = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE); - entry.setBitRate(Integer.parseInt((bitrate != null) ? bitrate : "0") / 1000); - String length = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); - entry.setDuration(Integer.parseInt(length) / 1000); - String artist = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); - if(artist != null) { - entry.setArtist(artist); - } - String album = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM); - if(album != null) { - entry.setAlbum(album); - } - metadata.release(); - } catch(Exception e) { - Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver"); - } - } - - entry.setTitle(title); - entry.setSuffix(FileUtil.getExtension(file.getName().replace(".complete", ""))); - - File albumArt = FileUtil.getAlbumArtFile(context, entry); - if (albumArt.exists()) { - entry.setCoverArt(albumArt.getPath()); - } - if(FileUtil.isVideoFile(file)) { - entry.setVideo(true); - } - return entry; - } - - @Override - public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, int saveSize, ProgressListener progressListener) throws Exception { - try { - return FileUtil.getAlbumArtBitmap(context, entry, size); - } catch(Exception e) { - return null; - } - } - - @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 { - List<Artist> artists = new ArrayList<Artist>(); - List<MusicDirectory.Entry> albums = new ArrayList<MusicDirectory.Entry>(); - List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(); - File root = FileUtil.getMusicDirectory(context); - int closeness = 0; - for (File artistFile : FileUtil.listFiles(root)) { - String artistName = artistFile.getName(); - if (artistFile.isDirectory()) { - if((closeness = matchCriteria(criteria, artistName)) > 0) { - Artist artist = new Artist(); - artist.setId(artistFile.getPath()); - artist.setIndex(artistFile.getName().substring(0, 1)); - artist.setName(artistName); - artist.setCloseness(closeness); - artists.add(artist); - } - - recursiveAlbumSearch(artistName, artistFile, criteria, context, albums, songs); - } - } - - Collections.sort(artists, new Comparator<Artist>() { - public int compare(Artist lhs, Artist rhs) { - if(lhs.getCloseness() == rhs.getCloseness()) { - return 0; - } - else if(lhs.getCloseness() > rhs.getCloseness()) { - return -1; - } - else { - return 1; - } - } - }); - Collections.sort(albums, new Comparator<MusicDirectory.Entry>() { - public int compare(MusicDirectory.Entry lhs, MusicDirectory.Entry rhs) { - if(lhs.getCloseness() == rhs.getCloseness()) { - return 0; - } - else if(lhs.getCloseness() > rhs.getCloseness()) { - return -1; - } - else { - return 1; - } - } - }); - Collections.sort(songs, new Comparator<MusicDirectory.Entry>() { - public int compare(MusicDirectory.Entry lhs, MusicDirectory.Entry rhs) { - if(lhs.getCloseness() == rhs.getCloseness()) { - return 0; - } - else if(lhs.getCloseness() > rhs.getCloseness()) { - return -1; - } - else { - return 1; - } - } - }); - - return new SearchResult(artists, albums, songs); - } - - private void recursiveAlbumSearch(String artistName, File file, SearchCritera criteria, Context context, List<MusicDirectory.Entry> albums, List<MusicDirectory.Entry> songs) { - int closeness; - for(File albumFile : FileUtil.listMediaFiles(file)) { - if(albumFile.isDirectory()) { - String albumName = getName(albumFile); - if((closeness = matchCriteria(criteria, albumName)) > 0) { - MusicDirectory.Entry album = createEntry(context, albumFile, albumName); - album.setArtist(artistName); - album.setCloseness(closeness); - albums.add(album); - } - - for(File songFile : FileUtil.listMediaFiles(albumFile)) { - String songName = getName(songFile); - if(songFile.isDirectory()) { - recursiveAlbumSearch(artistName, songFile, criteria, context, albums, songs); - } - else if((closeness = matchCriteria(criteria, songName)) > 0){ - MusicDirectory.Entry song = createEntry(context, albumFile, songName); - song.setArtist(artistName); - song.setAlbum(albumName); - song.setCloseness(closeness); - songs.add(song); - } - } - } - else { - String songName = getName(albumFile); - if((closeness = matchCriteria(criteria, songName)) > 0) { - MusicDirectory.Entry song = createEntry(context, albumFile, songName); - song.setArtist(artistName); - song.setAlbum(songName); - song.setCloseness(closeness); - songs.add(song); - } - } - } - } - private int matchCriteria(SearchCritera criteria, String name) { - String query = criteria.getQuery().toLowerCase(); - String[] queryParts = query.split(" "); - String[] nameParts = name.toLowerCase().split(" "); - - int closeness = 0; - for(String queryPart : queryParts) { - for(String namePart : nameParts) { - if(namePart.equals(queryPart)) { - closeness++; - } - } - } - - return closeness; - } - - @Override - public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List<Playlist> playlists = new ArrayList<Playlist>(); - File root = FileUtil.getPlaylistDirectory(); - String lastServer = null; - boolean removeServer = true; - for (File folder : FileUtil.listFiles(root)) { - if(folder.isDirectory()) { - String server = folder.getName(); - SortedSet<File> fileList = FileUtil.listFiles(folder); - for(File file: fileList) { - if(FileUtil.isPlaylistFile(file)) { - String id = file.getName(); - String filename = server + ": " + FileUtil.getBaseName(id); - Playlist playlist = new Playlist(server, filename); - playlists.add(playlist); - } - } - - if(!server.equals(lastServer) && fileList.size() > 0) { - if(lastServer != null) { - removeServer = false; - } - lastServer = server; - } - } else { - // Delete legacy playlist files - try { - folder.delete(); - } catch(Exception e) { - Log.w(TAG, "Failed to delete old playlist file: " + folder.getName()); - } - } - } - - if(removeServer) { - for(Playlist playlist: playlists) { - playlist.setName(playlist.getName().substring(playlist.getId().length() + 2)); - } - } - 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; - BufferedReader buffer = null; - try { - int firstIndex = name.indexOf(id); - if(firstIndex != -1) { - name = name.substring(id.length() + 2); - } - - File playlistFile = FileUtil.getPlaylistFile(id, name); - reader = new FileReader(playlistFile); - buffer = new BufferedReader(reader); - - MusicDirectory playlist = new MusicDirectory(); - String line = buffer.readLine(); - if(!"#EXTM3U".equals(line)) return playlist; - - while( (line = buffer.readLine()) != null ){ - File entryFile = new File(line); - String entryName = getName(entryFile); - if(entryFile.exists() && entryName != null){ - playlist.addChild(createEntry(context, entryFile, entryName)); - } - } - - return playlist; - } finally { - Util.close(buffer); - 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 void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Playlists not available in offline mode"); - } - - @Override - public void addToPlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Updating playlist not available in offline mode"); - } - - @Override - public void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Removing from playlist not available in offline mode"); - } - - @Override - public void overwritePlaylist(String id, String name, int toRemove, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Overwriting playlist not available in offline mode"); - } - - @Override - public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Updating playlist 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 { - if(!submission) { - return; - } - - SharedPreferences prefs = Util.getPreferences(context); - String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - - SharedPreferences offline = Util.getOfflineSync(context); - int scrobbles = offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - scrobbles++; - SharedPreferences.Editor offlineEditor = offline.edit(); - - if(id.indexOf(cacheLocn) != -1) { - String scrobbleSearchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn); - offlineEditor.putString(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles, scrobbleSearchCriteria); - offlineEditor.remove(Constants.OFFLINE_SCROBBLE_ID + scrobbles); - } else { - offlineEditor.putString(Constants.OFFLINE_SCROBBLE_ID + scrobbles, id); - offlineEditor.remove(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles); - } - - offlineEditor.putLong(Constants.OFFLINE_SCROBBLE_TIME + scrobbles, System.currentTimeMillis()); - offlineEditor.putInt(Constants.OFFLINE_SCROBBLE_COUNT, scrobbles); - offlineEditor.commit(); - } - - @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(int maxBitrate, Context context, String id) { - return null; - } - - @Override - public String getVideoStreamUrl(String format, int maxBitrate, Context context, String id) throws Exception { - return null; - } - - @Override - public String getHlsUrl(String id, int bitRate, Context context) throws Exception { - 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 void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception { - SharedPreferences prefs = Util.getPreferences(context); - String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - - SharedPreferences offline = Util.getOfflineSync(context); - int stars = offline.getInt(Constants.OFFLINE_STAR_COUNT, 0); - stars++; - SharedPreferences.Editor offlineEditor = offline.edit(); - - if(id.indexOf(cacheLocn) != -1) { - String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn); - offlineEditor.putString(Constants.OFFLINE_STAR_SEARCH + stars, searchCriteria); - offlineEditor.remove(Constants.OFFLINE_STAR_ID + stars); - } else { - offlineEditor.putString(Constants.OFFLINE_STAR_ID + stars, id); - offlineEditor.remove(Constants.OFFLINE_STAR_SEARCH + stars); - } - - offlineEditor.putBoolean(Constants.OFFLINE_STAR_SETTING + stars, starred); - offlineEditor.putInt(Constants.OFFLINE_STAR_COUNT, stars); - offlineEditor.commit(); - } - - @Override - public List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Getting Genres not available in offline mode"); - } - - @Override - public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Getting Songs By Genre not available in offline mode"); - } - - @Override - public MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, 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; - } - - @Override - public List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List<PodcastChannel> channels = new ArrayList<PodcastChannel>(); - - File dir = FileUtil.getPodcastDirectory(context); - String line; - for(File file: dir.listFiles()) { - BufferedReader br = new BufferedReader(new FileReader(file)); - while ((line = br.readLine()) != null && !"".equals(line)) { - PodcastChannel channel = new PodcastChannel(); - channel.setId(line); - channel.setName(line); - channel.setStatus("completed"); - - if(FileUtil.getPodcastDirectory(context, channel).exists()) { - channels.add(channel); - } - } - br.close(); - } - - return channels; - } - - @Override - public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { - return getMusicDirectory(FileUtil.getPodcastDirectory(context, id).getPath(), null, false, context, progressListener); - } - - @Override - public void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Getting Podcasts not available in offline mode"); - } - - @Override - public void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception{ - throw new OfflineException("Getting Podcasts not available in offline mode"); - } - - @Override - public void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception{ - throw new OfflineException("Getting Podcasts not available in offline mode"); - } - - @Override - public void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - throw new OfflineException("Getting Podcasts not available in offline mode"); - } - - @Override - public void deletePodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - throw new OfflineException("Getting Podcasts not available in offline mode"); - } - - @Override - public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ - throw new OfflineException("Offline scrobble cached can not be processes while in offline mode"); - } - - private void listFilesRecursively(File parent, List<File> children) { - for (File file : FileUtil.listMediaFiles(parent)) { - if (file.isFile()) { - children.add(file); - } else { - listFilesRecursively(file, children); - } - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java deleted file mode 100644 index e81c2b95..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java +++ /dev/null @@ -1,1296 +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 github.daneren2005.dsub.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 github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.*; -import github.daneren2005.dsub.domain.MusicDirectory.Entry; -import github.daneren2005.dsub.service.parser.AlbumListParser; -import github.daneren2005.dsub.service.parser.ChatMessageParser; -import github.daneren2005.dsub.service.parser.ErrorParser; -import github.daneren2005.dsub.service.parser.GenreParser; -import github.daneren2005.dsub.service.parser.IndexesParser; -import github.daneren2005.dsub.service.parser.JukeboxStatusParser; -import github.daneren2005.dsub.service.parser.LicenseParser; -import github.daneren2005.dsub.service.parser.LyricsParser; -import github.daneren2005.dsub.service.parser.MusicDirectoryParser; -import github.daneren2005.dsub.service.parser.MusicFoldersParser; -import github.daneren2005.dsub.service.parser.PlaylistParser; -import github.daneren2005.dsub.service.parser.PlaylistsParser; -import github.daneren2005.dsub.service.parser.PodcastChannelParser; -import github.daneren2005.dsub.service.parser.PodcastEntryParser; -import github.daneren2005.dsub.service.parser.RandomSongsParser; -import github.daneren2005.dsub.service.parser.SearchResult2Parser; -import github.daneren2005.dsub.service.parser.SearchResultParser; -import github.daneren2005.dsub.service.parser.ShareParser; -import github.daneren2005.dsub.service.parser.StarredListParser; -import github.daneren2005.dsub.service.parser.VersionParser; -import github.daneren2005.dsub.service.ssl.SSLSocketFactory; -import github.daneren2005.dsub.service.ssl.TrustSelfSignedStrategy; -import github.daneren2005.dsub.util.CancellableTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; -import java.io.*; - -/** - * @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 || refresh) ? 0L : cachedIndexes.getLastModified(); - - List<String> parameterNames = new ArrayList<String>(); - List<Object> parameterValues = new ArrayList<Object>(); - - if(lastModified != 0L) { - 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; - } - if(cachedIndexes != null) { - return cachedIndexes; - } else { - return new Indexes(0, new ArrayList<Artist>(), new ArrayList<Artist>()); - } - } 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, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - SharedPreferences prefs = Util.getPreferences(context); - String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - if(id.indexOf(cacheLocn) != -1) { - String search = Util.parseOfflineIDSearch(context, id, cacheLocn); - SearchCritera critera = new SearchCritera(search, 1, 1, 0); - SearchResult result = searchNew(critera, context, progressListener); - if(result.getArtists().size() == 1) { - id = result.getArtists().get(0).getId(); - } else if(result.getAlbums().size() == 1) { - id = result.getAlbums().get(0).getId(); - } - } - - Reader reader = getReader(context, progressListener, "getMusicDirectory", null, "id", id); - try { - return new MusicDirectoryParser(context).parse(name, 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); - try { - MusicDirectory playlist = new PlaylistParser(context).parse(reader, progressListener); - - File playlistFile = FileUtil.getPlaylistFile(Util.getServerName(context), name); - FileWriter fw = new FileWriter(playlistFile); - BufferedWriter bw = new BufferedWriter(fw); - try { - fw.write("#EXTM3U\n"); - for (MusicDirectory.Entry e : playlist.getChildren()) { - String filePath = FileUtil.getSongFile(context, e).getAbsolutePath(); - if(! new File(filePath).exists()){ - String ext = FileUtil.getExtension(filePath); - String base = FileUtil.getBaseName(filePath); - filePath = base + ".complete." + ext; - } - fw.write(filePath + "\n"); - } - } catch(Exception e) { - Log.w(TAG, "Failed to save playlist: " + name); - } finally { - bw.close(); - fw.close(); - } - - return playlist; - } 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(getOfflineSongId(entry.getId(), context, progressListener)); - } - - Reader reader = getReader(context, progressListener, "createPlaylist", null, parameterNames, parameterValues); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "deletePlaylist", null, "id", id); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void addToPlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlists is not supported."); - List<String> names = new ArrayList<String>(); - List<Object> values = new ArrayList<Object>(); - names.add("playlistId"); - values.add(id); - for(MusicDirectory.Entry song: toAdd) { - names.add("songIdToAdd"); - values.add(getOfflineSongId(song.getId(), context, progressListener)); - } - Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlists is not supported."); - List<String> names = new ArrayList<String>(); - List<Object> values = new ArrayList<Object>(); - names.add("playlistId"); - values.add(id); - for(Integer song: toRemove) { - names.add("songIndexToRemove"); - values.add(song); - } - Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void overwritePlaylist(String id, String name, int toRemove, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlists is not supported."); - List<String> names = new ArrayList<String>(); - List<Object> values = new ArrayList<Object>(); - names.add("playlistId"); - values.add(id); - names.add("name"); - values.add(name); - for(MusicDirectory.Entry song: toAdd) { - names.add("songIdToAdd"); - values.add(song.getId()); - } - for(int i = 0; i < toRemove; i++) { - names.add("songIndexToRemove"); - values.add(i); - } - Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlists is not supported."); - Reader reader = getReader(context, progressListener, "updatePlaylist", null, Arrays.asList("playlistId", "name", "comment", "public"), Arrays.<Object>asList(id, name, comment, pub)); - 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 { - id = getOfflineSongId(id, context, progressListener); - scrobble(id, submission, 0, context, progressListener); - } - - public void scrobble(String id, boolean submission, long time, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.5", "Scrobbling not supported."); - Reader reader; - if(time > 0){ - checkServerVersion(context, "1.8", "Scrobbling with a time not supported."); - reader = getReader(context, progressListener, "scrobble", null, Arrays.asList("id", "submission", "time"), Arrays.<Object>asList(id, submission, time)); - } - else - 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 getStarredList(Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getStarred", null); - try { - return new StarredListParser(context).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getRandomSongs(int size, String musicFolderId, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception { - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List<String> names = new ArrayList<String>(); - List<Object> values = new ArrayList<Object>(); - - names.add("size"); - values.add(size); - - if (musicFolderId != null && !"".equals(musicFolderId)) { - names.add("musicFolderId"); - values.add(musicFolderId); - } - if(genre != null && !"".equals(genre)) { - names.add("genre"); - values.add(genre); - } - if(startYear != null && !"".equals(startYear)) { - names.add("fromYear"); - values.add(startYear); - } - if(endYear != null && !"".equals(endYear)) { - names.add("toYear"); - values.add(endYear); - } - - Reader reader = getReader(context, progressListener, "getRandomSongs", params, names, values); - 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("github.daneren2005.dsub", 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, int saveSize, 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(), saveSize); - 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); - - File albumDir = FileUtil.getAlbumDirectory(context, entry); - if (albumDir.exists()) { - OutputStream out = null; - try { - out = new FileOutputStream(FileUtil.getAlbumArtFile(albumDir)); - out.write(bytes); - } finally { - Util.close(out); - } - } - - bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); - if(size != saveSize) { - bitmap = Bitmap.createScaledBitmap(bitmap, size, size, true); - } - return bitmap; - - } 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(int maxBitrate, Context context, String id) { - StringBuilder builder = new StringBuilder(Util.getRestUrl(context, "videoPlayer")); - builder.append("&id=").append(id); - builder.append("&maxBitRate=").append(maxBitrate); - builder.append("&autoplay=true"); - - String url = rewriteUrlWithRedirect(context, builder.toString()); - Log.i(TAG, "Using video URL: " + url); - return url; - } - - @Override - public String getVideoStreamUrl(String format, int maxBitrate, Context context, String id) throws Exception { - StringBuilder builder = new StringBuilder(Util.getRestUrl(context, "stream")); - builder.append("&id=").append(id); - if(!"raw".equals(format)) { - checkServerVersion(context, "1.9", "Video streaming not supported."); - builder.append("&maxBitRate=").append(maxBitrate); - } - builder.append("&format=").append(format); - - String url = rewriteUrlWithRedirect(context, builder.toString()); - Log.i(TAG, "Using video URL: " + url); - return url; - } - - @Override - public String getHlsUrl(String id, int bitRate, Context context) throws Exception { - checkServerVersion(context, "1.9", "HLS video streaming not supported."); - - StringBuilder builder = new StringBuilder(Util.getRestUrl(context, "hls")); - builder.append("&id=").append(id); - if(bitRate > 0) { - builder.append("&bitRate=").append(bitRate); - } - - String url = rewriteUrlWithRedirect(context, builder.toString()); - Log.i(TAG, "Using hls 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); - } - } - - @Override - public void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Starring is not supported."); - id = getOfflineSongId(id, context, progressListener); - - Reader reader = getReader(context, progressListener, starred ? "star" : "unstar", null, "id", id); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public List<Share> getShares(Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.6", "Shares not supported."); - - Reader reader = getReader(context, progressListener, "getShares", null); - try { - return new ShareParser(context).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.2", "Chat not supported."); - - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List<String> parameterNames = new ArrayList<String>(); - List<Object> parameterValues = new ArrayList<Object>(); - - parameterNames.add("since"); - parameterValues.add(since); - - Reader reader = getReader(context, progressListener, "getChatMessages", params, parameterNames, parameterValues); - - try { - return new ChatMessageParser(context).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.2", "Chat not supported."); - - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List<String> parameterNames = new ArrayList<String>(); - List<Object> parameterValues = new ArrayList<Object>(); - - parameterNames.add("message"); - parameterValues.add(message); - - Reader reader = getReader(context, progressListener, "addChatMessage", params, parameterNames, parameterValues); - - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Genres not supported."); - - Reader reader = getReader(context, progressListener, "getGenres", null); - try { - return new GenreParser(context).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Genres not supported."); - - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List<String> parameterNames = new ArrayList<String>(); - List<Object> parameterValues = new ArrayList<Object>(); - - parameterNames.add("genre"); - parameterValues.add(genre); - parameterNames.add("count"); - parameterValues.add(count); - parameterNames.add("offset"); - parameterValues.add(offset); - - Reader reader = getReader(context, progressListener, "getSongsByGenre", params, parameterNames, parameterValues); - - try { - return new RandomSongsParser(context).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Podcasts not supported."); - - Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("includeEpisodes"), Arrays.<Object>asList("false")); - try { - List<PodcastChannel> channels = new PodcastChannelParser(context).parse(reader, progressListener); - - String content = ""; - for(PodcastChannel channel: channels) { - content += channel.getName() + "\n"; - } - - File file = FileUtil.getPodcastFile(context, Util.getServerName(context)); - BufferedWriter bw = new BufferedWriter(new FileWriter(file)); - bw.write(content); - bw.close(); - - return channels; - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("id"), Arrays.<Object>asList(id)); - try { - return new PodcastEntryParser(context).parse(id, reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Refresh podcasts not supported."); - - Reader reader = getReader(context, progressListener, "refreshPodcasts", null); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception{ - checkServerVersion(context, "1.9", "Creating podcasts not supported."); - - Reader reader = getReader(context, progressListener, "createPodcastChannel", null, "url", url); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Deleting podcasts not supported."); - - Reader reader = getReader(context, progressListener, "deletePodcastChannel", null, "id", id); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - checkServerVersion(context, "1.9", "Downloading podcasts not supported."); - - Reader reader = getReader(context, progressListener, "downloadPodcastEpisode", null, "id", id); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void deletePodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - checkServerVersion(context, "1.9", "Deleting podcasts not supported."); - - Reader reader = getReader(context, progressListener, "deletePodcastEpisode", null, "id", id); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ - return processOfflineScrobbles(context, progressListener) + processOfflineStars(context, progressListener); - } - - public int processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception { - SharedPreferences offline = Util.getOfflineSync(context); - SharedPreferences.Editor offlineEditor = offline.edit(); - int count = offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - int retry = 0; - for(int i = 1; i <= count; i++) { - String id = offline.getString(Constants.OFFLINE_SCROBBLE_ID + i, null); - long time = offline.getLong(Constants.OFFLINE_SCROBBLE_TIME + i, 0); - if(id != null) { - scrobble(id, true, time, context, progressListener); - } else { - String search = offline.getString(Constants.OFFLINE_SCROBBLE_SEARCH + i, ""); - try{ - SearchCritera critera = new SearchCritera(search, 0, 0, 1); - SearchResult result = searchNew(critera, context, progressListener); - if(result.getSongs().size() == 1){ - Log.i(TAG, "Query '" + search + "' returned song " + result.getSongs().get(0).getTitle() + " by " + result.getSongs().get(0).getArtist() + " with id " + result.getSongs().get(0).getId()); - Log.i(TAG, "Scrobbling " + result.getSongs().get(0).getId() + " with time " + time); - scrobble(result.getSongs().get(0).getId(), true, time, context, progressListener); - } - else{ - throw new Exception("Song not found on server"); - } - } - catch(Exception e){ - Log.e(TAG, e.toString()); - retry++; - } - } - } - - offlineEditor.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - offlineEditor.commit(); - - return count - retry; - } - - public int processOfflineStars(final Context context, final ProgressListener progressListener) throws Exception { - SharedPreferences offline = Util.getOfflineSync(context); - SharedPreferences.Editor offlineEditor = offline.edit(); - int count = offline.getInt(Constants.OFFLINE_STAR_COUNT, 0); - int retry = 0; - for(int i = 1; i <= count; i++) { - String id = offline.getString(Constants.OFFLINE_STAR_ID + i, null); - boolean starred = offline.getBoolean(Constants.OFFLINE_STAR_SETTING + i, false); - if(id != null) { - setStarred(id, starred, context, progressListener); - } else { - String search = offline.getString(Constants.OFFLINE_STAR_SEARCH + i, ""); - try{ - SearchCritera critera = new SearchCritera(search, 0, 1, 1); - SearchResult result = searchNew(critera, context, progressListener); - if(result.getSongs().size() == 1){ - Log.i(TAG, "Query '" + search + "' returned song " + result.getSongs().get(0).getTitle() + " by " + result.getSongs().get(0).getArtist() + " with id " + result.getSongs().get(0).getId()); - setStarred(result.getSongs().get(0).getId(), starred, context, progressListener); - } else if(result.getAlbums().size() == 1){ - Log.i(TAG, "Query '" + search + "' returned song " + result.getAlbums().get(0).getTitle() + " by " + result.getAlbums().get(0).getArtist() + " with id " + result.getAlbums().get(0).getId()); - setStarred(result.getAlbums().get(0).getId(), starred, context, progressListener); - } - else{ - throw new Exception("Song not found on server"); - } - } - catch(Exception e){ - Log.e(TAG, e.toString()); - retry++; - } - } - } - - offlineEditor.putInt(Constants.OFFLINE_STAR_COUNT, 0); - offlineEditor.commit(); - - return count - retry; - } - - private String getOfflineSongId(String id, Context context, ProgressListener progressListener) throws Exception { - SharedPreferences prefs = Util.getPreferences(context); - String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - if(id.indexOf(cacheLocn) != -1) { - String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn); - SearchCritera critera = new SearchCritera(searchCriteria, 0, 0, 1); - SearchResult result = searchNew(critera, context, progressListener); - if(result.getSongs().size() == 1){ - id = result.getSongs().get(0).getId(); - } - } - - return id; - } - - 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 { - // Strip out sensitive information from log - Log.i(TAG, "Using URL " + url.substring(0, url.indexOf("?u=") + 1) + url.substring(url.indexOf("&v=") + 1)); - - SharedPreferences prefs = Util.getPreferences(context); - int networkTimeout = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT, "15000")); - HttpParams newParams = httpClient.getParams(); - HttpConnectionParams.setSoTimeout(newParams, networkTimeout); - httpClient.setParams(newParams); - - 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() { - new Thread(new Runnable() { - public void run() { - try { - cancelled.set(true); - request.abort(); - } catch(Exception e) { - Log.e(TAG, "Failed to stop http task"); - } - } - }).start(); - } - }); - } - - 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. - 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); - - // Sometimes the request doesn't contain the "http://host" part - String redirectedUrl; - if (request.getURI().getScheme() == null) { - redirectedUrl = host.toURI() + request.getURI(); - } else { - redirectedUrl = request.getURI().toString(); - } - - redirectFrom = originalUrl.substring(0, originalUrl.indexOf("/rest/")); - redirectTo = redirectedUrl.substring(0, redirectedUrl.indexOf("/rest/")); - - if(redirectFrom.compareTo(redirectTo) != 0) { - 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/github/daneren2005/dsub/service/Scrobbler.java b/subsonic-android/src/github/daneren2005/dsub/service/Scrobbler.java deleted file mode 100644 index 222c78c8..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/Scrobbler.java +++ /dev/null @@ -1,52 +0,0 @@ -package github.daneren2005.dsub.service; - -import android.content.Context; -import android.util.Log; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/ServerTooOldException.java b/subsonic-android/src/github/daneren2005/dsub/service/ServerTooOldException.java deleted file mode 100644 index e4a951de..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/ServerTooOldException.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 github.daneren2005.dsub.service; - -import github.daneren2005.dsub.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 server version ") - .append(requiredVersion.getVersion()) - .append(", but it is version ") - .append(serverVersion.getVersion()) - .append("."); - return builder.toString(); - } - - @Override - public String getMessage() { - return this.toString(); - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/StreamProxy.java b/subsonic-android/src/github/daneren2005/dsub/service/StreamProxy.java deleted file mode 100644 index 24c1b201..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/StreamProxy.java +++ /dev/null @@ -1,248 +0,0 @@ -package github.daneren2005.dsub.service;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-import java.net.URLDecoder;
-import java.net.UnknownHostException;
-import java.util.StringTokenizer;
-
-import org.apache.http.HttpRequest;
-import org.apache.http.message.BasicHttpRequest;
-
-import android.os.AsyncTask;
-import android.os.Looper;
-import android.util.Log;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.util.Constants;
-
-public class StreamProxy implements Runnable {
- private static final String TAG = StreamProxy.class.getSimpleName();
-
- private Thread thread;
- private boolean isRunning;
- private ServerSocket socket;
- private int port;
- private DownloadService downloadService;
-
- public StreamProxy(DownloadService downloadService) {
-
- // Create listening socket
- try {
- socket = new ServerSocket(0, 0, InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }));
- socket.setSoTimeout(5000);
- port = socket.getLocalPort();
- this.downloadService = downloadService;
- } catch (UnknownHostException e) { // impossible
- } catch (IOException e) {
- Log.e(TAG, "IOException initializing server", e);
- }
- }
-
- public int getPort() {
- return port;
- }
-
- public void start() {
- thread = new Thread(this);
- thread.start();
- }
-
- public void stop() {
- isRunning = false;
- thread.interrupt();
- }
-
- @Override
- public void run() {
- isRunning = true;
- while (isRunning) {
- try {
- Socket client = socket.accept();
- if (client == null) {
- continue;
- }
- Log.i(TAG, "client connected");
-
- StreamToMediaPlayerTask task = new StreamToMediaPlayerTask(client);
- if (task.processRequest()) {
- new Thread(task).start();
- }
-
- } catch (SocketTimeoutException e) {
- // Do nothing
- } catch (IOException e) {
- Log.e(TAG, "Error connecting to client", e);
- }
- }
- Log.i(TAG, "Proxy interrupted. Shutting down.");
- }
-
- private class StreamToMediaPlayerTask implements Runnable {
-
- String localPath;
- Socket client;
- int cbSkip;
-
- public StreamToMediaPlayerTask(Socket client) {
- this.client = client;
- }
-
- private HttpRequest readRequest() {
- HttpRequest request = null;
- InputStream is;
- String firstLine;
- try {
- is = client.getInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8192);
- firstLine = reader.readLine();
- } catch (IOException e) {
- Log.e(TAG, "Error parsing request", e);
- return request;
- }
-
- if (firstLine == null) {
- Log.i(TAG, "Proxy client closed connection without a request.");
- return request;
- }
-
- StringTokenizer st = new StringTokenizer(firstLine);
- String method = st.nextToken();
- String uri = st.nextToken();
- String realUri = uri.substring(1);
- Log.i(TAG, realUri);
- request = new BasicHttpRequest(method, realUri);
- return request;
- }
-
- public boolean processRequest() {
- HttpRequest request = readRequest();
- if (request == null) {
- return false;
- }
-
- // Read HTTP headers
- Log.i(TAG, "Processing request");
-
- try {
- localPath = URLDecoder.decode(request.getRequestLine().getUri(), Constants.UTF_8);
- } catch (UnsupportedEncodingException e) {
- Log.e(TAG, "Unsupported encoding", e);
- return false;
- }
-
- Log.i(TAG, "Processing request for file " + localPath);
- File file = new File(localPath);
- if (!file.exists()) {
- Log.e(TAG, "File " + localPath + " does not exist");
- return false;
- }
-
- return true;
- }
-
- @Override
- public void run() {
- Log.i(TAG, "Streaming song in background");
- DownloadFile downloadFile = downloadService.getCurrentPlaying();
- MusicDirectory.Entry song = downloadFile.getSong();
-
- // Create HTTP header
- String headers = "HTTP/1.0 200 OK\r\n";
- headers += "Content-Type: " + "application/octet-stream" + "\r\n";
-
- Integer contentLength = downloadFile.getContentLength();
- long fileSize;
- if(contentLength == null) {
- fileSize = downloadFile.getBitRate() * ((song.getDuration() != null) ? song.getDuration() : 0) * 1000 / 8;
- } else {
- fileSize = contentLength;
- headers += "Content-Length: " + fileSize + "\r\n";
- }
- Log.i(TAG, "Streaming fileSize: " + fileSize);
-
- headers += "Connection: close\r\n";
- headers += "\r\n";
-
- long cbToSend = fileSize - cbSkip;
- OutputStream output = null;
- byte[] buff = new byte[64 * 1024];
- try {
- output = new BufferedOutputStream(client.getOutputStream(), 32*1024);
- output.write(headers.getBytes());
-
- if(!downloadFile.isWorkDone()) {
- // Loop as long as there's stuff to send
- while (isRunning && !client.isClosed()) {
-
- // See if there's more to send
- File file = new File(localPath);
- int cbSentThisBatch = 0;
- if (file.exists()) {
- FileInputStream input = new FileInputStream(file);
- input.skip(cbSkip);
- int cbToSendThisBatch = input.available();
- while (cbToSendThisBatch > 0) {
- int cbToRead = Math.min(cbToSendThisBatch, buff.length);
- int cbRead = input.read(buff, 0, cbToRead);
- if (cbRead == -1) {
- break;
- }
- cbToSendThisBatch -= cbRead;
- cbToSend -= cbRead;
- output.write(buff, 0, cbRead);
- output.flush();
- cbSkip += cbRead;
- cbSentThisBatch += cbRead;
- }
- input.close();
- }
-
- // Done regardless of whether or not it thinks it is
- if(downloadFile.isWorkDone() && cbSkip >= file.length()) {
- break;
- }
-
- // If we did nothing this batch, block for a second
- if (cbSentThisBatch == 0) {
- Log.d(TAG, "Blocking until more data appears (" + cbToSend + ")");
- Thread.sleep(1000);
- }
- }
- } else {
- Log.w(TAG, "Requesting data for completely downloaded file");
- }
- }
- catch (SocketException socketException) {
- Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
- }
- catch (Exception e) {
- Log.e(TAG, "Exception thrown from streaming task:");
- Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
- }
-
- // Cleanup
- try {
- if (output != null) {
- output.close();
- }
- client.close();
- }
- catch (IOException e) {
- Log.e(TAG, "IOException while cleaning up streaming task:");
- Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
- }
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/AbstractParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/AbstractParser.java deleted file mode 100644 index 1a457754..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import java.io.Reader; - -import org.xmlpull.v1.XmlPullParser; - -import android.content.Context; -import android.util.Xml; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Version; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - */ -public abstract class AbstractParser { - - protected 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/github/daneren2005/dsub/service/parser/AlbumListParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/AlbumListParser.java deleted file mode 100644 index 64145d67..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/ChatMessageParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/ChatMessageParser.java deleted file mode 100644 index 1425a734..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/ChatMessageParser.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 github.daneren2005.dsub.service.parser;
-
-import android.content.Context;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.ChatMessage;
-import github.daneren2005.dsub.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Joshua Bahnsen
- */
-public class ChatMessageParser extends AbstractParser {
-
- public ChatMessageParser(Context context) {
- super(context);
- }
-
- public List<ChatMessage> parse(Reader reader, ProgressListener progressListener) throws Exception {
- updateProgress(progressListener, R.string.parser_reading);
- init(reader);
- List<ChatMessage> result = new ArrayList<ChatMessage>();
- int eventType;
-
- do {
- eventType = nextParseEvent();
- if (eventType == XmlPullParser.START_TAG) {
- String name = getElementName();
- if ("chatMessage".equals(name)) {
- ChatMessage chatMessage = new ChatMessage();
- chatMessage.setUsername(get("username"));
- chatMessage.setTime(getLong("time"));
- chatMessage.setMessage(get("message"));
- result.add(chatMessage);
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return result;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/ErrorParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/ErrorParser.java deleted file mode 100644 index 3463687d..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/GenreParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/GenreParser.java deleted file mode 100644 index 1062d3af..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/GenreParser.java +++ /dev/null @@ -1,122 +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 github.daneren2005.dsub.service.parser;
-
-import android.content.Context;
-import android.util.Log;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Genre;
-import github.daneren2005.dsub.util.ProgressListener;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Joshua Bahnsen
- */
-public class GenreParser extends AbstractParser {
- private static final String TAG = GenreParser.class.getSimpleName();
-
- public GenreParser(Context context) {
- super(context);
- }
-
- public List<Genre> parse(Reader reader, ProgressListener progressListener) throws Exception {
- updateProgress(progressListener, R.string.parser_reading);
-
- List<Genre> result = new ArrayList<Genre>();
- StringReader sr = null;
-
- try {
- BufferedReader br = new BufferedReader(reader);
- String xml = null;
- String line = null;
-
- while ((line = br.readLine()) != null) {
- if (xml == null) {
- xml = line;
- } else {
- xml += line;
- }
- }
- br.close();
-
- // Replace double escaped ampersand (&apos;)
- xml = xml.replaceAll("(?:&)(amp;|lt;|gt;|#37;|apos;)", "&$1");
-
- // Replace unescaped ampersand
- xml = xml.replaceAll("&(?!amp;|lt;|gt;|#37;|apos;)", "&");
-
- // Replace unescaped percent symbol
- // No replacements for <> at this time
- xml = xml.replaceAll("%", "%");
-
- xml = xml.replaceAll("'", "'");
-
- sr = new StringReader(xml);
- } catch (IOException ioe) {
- Log.e(TAG, "Error parsing Genre XML", ioe);
- }
-
- if (sr == null) {
- Log.w(TAG, "Unable to parse Genre XML, returning empty list");
- return result;
- }
-
- init(sr);
-
- Genre genre = null;
-
- int eventType;
- do {
- eventType = nextParseEvent();
- if (eventType == XmlPullParser.START_TAG) {
- String name = getElementName();
- if ("genre".equals(name)) {
- genre = new Genre();
- } else if ("error".equals(name)) {
- handleError();
- } else {
- genre = null;
- }
- } else if (eventType == XmlPullParser.TEXT) {
- if (genre != null) {
- String value = getText();
- if (genre != null) {
- genre.setName(value);
- genre.setIndex(value.substring(0, 1));
- result.add(genre);
- genre = null;
- }
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return result;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/IndexesParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/IndexesParser.java deleted file mode 100644 index 6196411d..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/IndexesParser.java +++ /dev/null @@ -1,120 +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 github.daneren2005.dsub.service.parser; - -import java.io.Reader; -import java.util.List; -import java.util.ArrayList; - -import org.xmlpull.v1.XmlPullParser; - -import android.content.Context; -import android.content.SharedPreferences; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.util.ProgressListener; -import android.util.Log; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - */ -public class IndexesParser extends AbstractParser { - private static final String TAG = IndexesParser.class.getSimpleName(); - - private Context context; - - public IndexesParser(Context context) { - super(context); - this.context = 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 = "#"; - String ignoredArticles = null; - boolean changed = false; - - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("indexes".equals(name)) { - changed = true; - lastModified = getLong("lastModified"); - ignoredArticles = get("ignoredArticles"); - } else if ("index".equals(name)) { - index = get("name"); - - } else if ("artist".equals(name)) { - Artist artist = new Artist(); - artist.setId(get("id")); - artist.setName(get("name")); - artist.setIndex(index); - artist.setStarred(get("starred") != null); - 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("*"); - shortcut.setStarred(get("starred") != null); - shortcuts.add(shortcut); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - if(ignoredArticles != null) { - SharedPreferences.Editor prefs = Util.getPreferences(context).edit(); - prefs.putString(Constants.CACHE_KEY_IGNORE, ignoredArticles); - prefs.commit(); - } - - 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/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java deleted file mode 100644 index 8526e635..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import java.io.Reader; - -import org.xmlpull.v1.XmlPullParser; - -import android.content.Context; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/LicenseParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/LicenseParser.java deleted file mode 100644 index e7b200fd..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/LyricsParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/LyricsParser.java deleted file mode 100644 index 98b0f6a0..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java deleted file mode 100644 index b0434aca..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java +++ /dev/null @@ -1,74 +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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.domain.MusicDirectory; - -/** - * @author Sindre Mehus - */ -public class MusicDirectoryEntryParser extends AbstractParser { - public MusicDirectoryEntryParser(Context context) { - super(context); - } - - protected MusicDirectory.Entry parseEntry(String artist) { - 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")); - entry.setStarred(get("starred") != null); - - 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")); - entry.setDiscNumber(getInteger("discNumber")); - } else if(!"".equals(artist)) { - entry.setPath(artist + "/" + entry.getTitle()); - } - return entry; - } - - protected MusicDirectory.Entry parseArtist() { - MusicDirectory.Entry entry = new MusicDirectory.Entry(); - - entry.setId(get("id")); - entry.setTitle(get("name")); - entry.setPath(entry.getTitle()); - entry.setStarred(true); - entry.setDirectory(true); - - return entry; - } -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java deleted file mode 100644 index 17b09805..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java +++ /dev/null @@ -1,83 +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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import android.util.Log; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.Version; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; -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(); - private Context context; - - public MusicDirectoryParser(Context context) { - super(context); - this.context = context; - } - - public MusicDirectory parse(String artist, 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)) { - MusicDirectory.Entry entry = parseEntry(artist); - entry.setGrandParent(dir.getParent()); - dir.addChild(entry); - } else if ("directory".equals(name)) { - dir.setName(get("name")); - dir.setId(get("id")); - dir.setParent(get("parent")); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - updateProgress(progressListener, R.string.parser_reading_done); - - // Only apply sorting on server version 4.7 and greater, where disc is supported - if(Util.checkServerVersion(context, "1.8.0")) { - dir.sortChildren(); - } - - 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/github/daneren2005/dsub/service/parser/MusicFoldersParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicFoldersParser.java deleted file mode 100644 index 5dfebf27..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; - -import org.xmlpull.v1.XmlPullParser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/PlaylistParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PlaylistParser.java deleted file mode 100644 index 8c6cfc6f..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/PlaylistsParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PlaylistsParser.java deleted file mode 100644 index a5bf2497..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/PlaylistsParser.java +++ /dev/null @@ -1,73 +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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.view.PlaylistAdapter; -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"); - String owner = get("owner"); - String comment = get("comment"); - String songCount = get("songCount"); - String created = get("created"); - String pub = get("public"); - result.add(new Playlist(id, name, owner, comment, songCount, created, pub)); - } else if ("error".equals(tag)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - updateProgress(progressListener, R.string.parser_reading_done); - - return PlaylistAdapter.PlaylistComparator.sort(result); - } - -}
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java deleted file mode 100644 index b091aefa..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.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 github.daneren2005.dsub.service.parser;
-
-import android.content.Context;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.PodcastChannel;
-import github.daneren2005.dsub.util.ProgressListener;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- *
- * @author Scott
- */
-public class PodcastChannelParser extends AbstractParser {
- public PodcastChannelParser(Context context) {
- super(context);
- }
-
- public List<PodcastChannel> parse(Reader reader, ProgressListener progressListener) throws Exception {
- updateProgress(progressListener, R.string.parser_reading);
- init(reader);
-
- List<PodcastChannel> channels = new ArrayList<PodcastChannel>();
- int eventType;
- do {
- eventType = nextParseEvent();
- if (eventType == XmlPullParser.START_TAG) {
- String name = getElementName();
- if ("channel".equals(name)) {
- PodcastChannel channel = new PodcastChannel();
- channel.setId(get("id"));
- channel.setUrl(get("url"));
- channel.setName(get("title"));
- channel.setDescription(get("description"));
- channel.setStatus(get("status"));
- channel.setErrorMessage(get("errorMessage"));
- channels.add(channel);
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- return channels;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java deleted file mode 100644 index 585b3057..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java +++ /dev/null @@ -1,105 +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 github.daneren2005.dsub.service.parser;
-
-import android.content.Context;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.PodcastEpisode;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.ProgressListener;
-import java.io.Reader;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- *
- * @author Scott
- */
-public class PodcastEntryParser extends AbstractParser {
- private static int bogusId = -1;
-
- public PodcastEntryParser(Context context) {
- super(context);
- }
-
- public MusicDirectory parse(String channel, Reader reader, ProgressListener progressListener) throws Exception {
- updateProgress(progressListener, R.string.parser_reading);
- init(reader);
-
- MusicDirectory episodes = new MusicDirectory();
- int eventType;
- boolean valid = false;
- do {
- eventType = nextParseEvent();
- if (eventType == XmlPullParser.START_TAG) {
- String name = getElementName();
- if ("channel".equals(name)) {
- String id = get("id");
- if(id.equals(channel)) {
- episodes.setId(id);
- episodes.setName(get("title"));
- valid = true;
- } else {
- valid = false;
- }
- }
- else if ("episode".equals(name) && valid) {
- PodcastEpisode episode = new PodcastEpisode();
- episode.setEpisodeId(get("id"));
- episode.setId(get("streamId"));
- episode.setTitle(get("title"));
- episode.setArtist(episodes.getName());
- episode.setAlbum(get("description"));
- episode.setDate(get("publishDate"));
- if(episode.getDate() == null) {
- episode.setDate(get("created"));
- }
- if(episode.getDate() != null && episode.getDate().indexOf("T") != -1) {
- episode.setDate(episode.getDate().replace("T", " "));
- }
- episode.setStatus(get("status"));
- episode.setCoverArt(get("coverArt"));
- episode.setSize(getLong("size"));
- episode.setContentType(get("contentType"));
- episode.setSuffix(get("suffix"));
- episode.setDuration(getInteger("duration"));
- episode.setBitRate(getInteger("bitRate"));
- episode.setVideo(getBoolean("isVideo"));
- episode.setPath(get("path"));
- if(episode.getPath() == null) {
- episode.setPath(FileUtil.getPodcastPath(context, episode));
- } else if(episode.getPath().indexOf("Podcasts/") == 0) {
- episode.setPath(episode.getPath().substring("Podcasts/".length()));
- }
-
- if("error".equals(episode.getStatus()) || "skipped".equals(episode.getStatus())) {
- episode.setId(String.valueOf(bogusId));
- bogusId--;
- }
- episodes.addChild(episode);
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- return episodes;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/RandomSongsParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/RandomSongsParser.java deleted file mode 100644 index 3e62d3dc..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/SearchResult2Parser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/SearchResult2Parser.java deleted file mode 100644 index a0be07ac..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/SearchResultParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/SearchResultParser.java deleted file mode 100644 index c8ef4031..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/ShareParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/ShareParser.java deleted file mode 100644 index c317e799..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/ShareParser.java +++ /dev/null @@ -1,77 +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 github.daneren2005.dsub.service.parser;
-
-import android.content.Context;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Share;
-import github.daneren2005.dsub.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Joshua Bahnsen
- */
-public class ShareParser extends MusicDirectoryEntryParser {
-
- public ShareParser(Context context) {
- super(context);
- }
-
- public List<Share> parse(Reader reader, ProgressListener progressListener) throws Exception {
-
- updateProgress(progressListener, R.string.parser_reading);
- init(reader);
-
- List<Share> dir = new ArrayList<Share>();
- Share share = null;
- int eventType;
-
- do {
- eventType = nextParseEvent();
-
- if (eventType == XmlPullParser.START_TAG) {
- String name = getElementName();
-
- if ("share".equals(name)) {
- share = new Share();
- share.setCreated(get("created"));
- share.setDescription(get("description"));
- share.setExpires(get("expires"));
- share.setId(get("id"));
- share.setLastVisited(get("lastVisited"));
- share.setUrl(get("url"));
- share.setUsername(get("username"));
- share.setVisitCount(getLong("visitCount"));
- } else if ("entry".equals(name)) {
- share.addEntry(parseEntry(null));
- } 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/github/daneren2005/dsub/service/parser/StarredListParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/StarredListParser.java deleted file mode 100644 index fc4cd175..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/StarredListParser.java +++ /dev/null @@ -1,64 +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 github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -/** - * @author Kurt Hardin - */ -public class StarredListParser extends MusicDirectoryEntryParser { - - public StarredListParser(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) || "song".equals(name)) { - dir.addChild(parseEntry("")); - } else if("artist".equals(name)) { - dir.addChild(parseArtist()); - } 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/github/daneren2005/dsub/service/parser/SubsonicRESTException.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/SubsonicRESTException.java deleted file mode 100644 index 096597a1..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/SubsonicRESTException.java +++ /dev/null @@ -1,19 +0,0 @@ -package github.daneren2005.dsub.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/github/daneren2005/dsub/service/parser/VersionParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/VersionParser.java deleted file mode 100644 index 1b646206..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.service.parser; - -import github.daneren2005.dsub.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/github/daneren2005/dsub/service/ssl/SSLSocketFactory.java b/subsonic-android/src/github/daneren2005/dsub/service/ssl/SSLSocketFactory.java deleted file mode 100644 index 2ffed048..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/service/ssl/TrustManagerDecorator.java b/subsonic-android/src/github/daneren2005/dsub/service/ssl/TrustManagerDecorator.java deleted file mode 100644 index f2364368..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/service/ssl/TrustSelfSignedStrategy.java b/subsonic-android/src/github/daneren2005/dsub/service/ssl/TrustSelfSignedStrategy.java deleted file mode 100644 index 637a8931..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/service/ssl/TrustStrategy.java b/subsonic-android/src/github/daneren2005/dsub/service/ssl/TrustStrategy.java deleted file mode 100644 index 334a97c5..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/updates/Updater.java b/subsonic-android/src/github/daneren2005/dsub/updates/Updater.java deleted file mode 100644 index 60a17b67..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/updates/Updater.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 github.daneren2005.dsub.updates;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.AsyncTask;
-import android.util.Log;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.Util;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- *
- * @author Scott
- */
-public class Updater {
- protected String TAG = Updater.class.getSimpleName();
- protected int version;
- protected Context context;
-
- public Updater(int version) {
- this.version = version;
- }
-
- public void checkUpdates(Context context) {
- this.context = context;
- List<Updater> updaters = new ArrayList<Updater>();
- updaters.add(new Updater403());
-
- SharedPreferences prefs = Util.getPreferences(context);
- int lastVersion = prefs.getInt(Constants.LAST_VERSION, 0);
- if(lastVersion == 0) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(Constants.LAST_VERSION, version);
- editor.commit();
- }
- else if(version > lastVersion) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(Constants.LAST_VERSION, version);
- editor.commit();
-
- Log.i(TAG, "Updating from version " + lastVersion + " to " + version);
- for(Updater updater: updaters) {
- if(updater.shouldUpdate(lastVersion)) {
- new BackgroundUpdate().execute(updater);
- }
- }
- }
- }
-
- public String getName() {
- return this.TAG;
- }
-
- private class BackgroundUpdate extends AsyncTask<Updater, Void, Void> {
- @Override
- protected Void doInBackground(Updater... params) {
- try {
- params[0].update(context);
- } catch(Exception e) {
- Log.w(TAG, "Failed to run update for " + params[0].getName());
- }
- return null;
- }
- }
-
- public boolean shouldUpdate(int version) {
- return this.version > version;
- }
- public void update(Context context) {
-
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/updates/Updater403.java b/subsonic-android/src/github/daneren2005/dsub/updates/Updater403.java deleted file mode 100644 index 17947ce5..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/updates/Updater403.java +++ /dev/null @@ -1,58 +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 github.daneren2005.dsub.updates;
-
-import android.content.Context;
-import android.util.Log;
-import github.daneren2005.dsub.updates.Updater;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.FileUtil;
-import java.io.File;
-
-/**
- *
- * @author Scott
- */
-public class Updater403 extends Updater {
- public Updater403() {
- super(403);
- TAG = Updater403.class.getSimpleName();
- }
-
- @Override
- public void update(Context context) {
- // Rename cover.jpeg to cover.jpg
- Log.i(TAG, "Running Updater403: updating cover.jpg to albumart.jpg");
- File dir = FileUtil.getMusicDirectory(context);
- if(dir != null) {
- moveArt(dir);
- }
- }
-
- private void moveArt(File dir) {
- for(File file: dir.listFiles()) {
- if(file.isDirectory()) {
- moveArt(file);
- } else if("cover.jpg".equals(file.getName()) || "cover.jpeg".equals(file.getName())) {
- File renamed = new File(dir, Constants.ALBUM_ART_FILE);
- file.renameTo(renamed);
- }
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/BackgroundTask.java b/subsonic-android/src/github/daneren2005/dsub/util/BackgroundTask.java deleted file mode 100644 index 547bbd1e..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/BackgroundTask.java +++ /dev/null @@ -1,97 +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 github.daneren2005.dsub.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 github.daneren2005.dsub.R; -import github.daneren2005.dsub.view.ErrorDialog; - -/** - * @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/github/daneren2005/dsub/util/CacheCleaner.java b/subsonic-android/src/github/daneren2005/dsub/util/CacheCleaner.java deleted file mode 100644 index 62204c76..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/CacheCleaner.java +++ /dev/null @@ -1,239 +0,0 @@ -package github.daneren2005.dsub.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.os.AsyncTask; -import android.util.Log; -import android.os.StatFs; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.DownloadService; -import java.util.*; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class CacheCleaner { - - private static final String TAG = CacheCleaner.class.getSimpleName(); - private static final long MIN_FREE_SPACE = 500 * 1024L * 1024L; - - private final Context context; - private final DownloadService downloadService; - - public CacheCleaner(Context context, DownloadService downloadService) { - this.context = context; - this.downloadService = downloadService; - } - - public void clean() { - new BackgroundCleanup().execute(); - } - public void cleanSpace() { - new BackgroundSpaceCleanup().execute(); - } - public void cleanPlaylists(List<Playlist> playlists) { - new BackgroundPlaylistsCleanup().execute(playlists); - } - - private void deleteEmptyDirs(List<File> dirs, Set<File> undeletable) { - for (File dir : dirs) { - if (undeletable.contains(dir)) { - continue; - } - - File[] children = dir.listFiles(); - - // No songs left in the folder - if(children.length == 1 && children[0].getPath().equals(FileUtil.getAlbumArtFile(dir).getPath())) { - Util.delete(children[0]); - children = dir.listFiles(); - } - - // Delete empty directory - if (children.length == 0) { - Util.delete(dir); - } - } - } - - private long getMinimumDelete(List<File> files) { - if(files.size() == 0) { - return 0L; - } - - long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L; - - long bytesUsedBySubsonic = 0L; - for (File file : files) { - bytesUsedBySubsonic += file.length(); - } - - // Ensure that file system is not more than 95% full. - StatFs stat = new StatFs(files.get(0).getPath()); - long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize(); - long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); - long bytesUsedFs = bytesTotalFs - bytesAvailableFs; - long minFsAvailability = bytesTotalFs - MIN_FREE_SPACE; - - 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)); - - return bytesToDelete; - } - - private void deleteFiles(List<File> files, Set<File> undeletable, long bytesToDelete, boolean deletePartials) { - if (files.isEmpty()) { - return; - } - - long bytesDeleted = 0L; - for (File file : files) { - if(!deletePartials && bytesDeleted > bytesToDelete) break; - - if (bytesToDelete > bytesDeleted || (deletePartials && (file.getName().endsWith(".partial") || file.getName().contains(".partial.")))) { - if (!undeletable.contains(file) && !file.getName().equals(Constants.ALBUM_ART_FILE)) { - long size = file.length(); - if (Util.delete(file)) { - bytesDeleted += size; - } - } - } - } - - Log.i(TAG, "Deleted : " + Util.formatBytes(bytesDeleted)); - } - - private void findCandidatesForDeletion(File file, List<File> files, List<File> dirs) { - if (file.isFile()) { - String name = file.getName(); - boolean isCacheFile = name.endsWith(".partial") || name.contains(".partial.") || name.endsWith(".complete") || name.contains(".complete."); - if (isCacheFile) { - files.add(file); - } - } else { - // Depth-first - for (File child : FileUtil.listFiles(file)) { - findCandidatesForDeletion(child, files, dirs); - } - dirs.add(file); - } - } - - private 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; - } - - private class BackgroundCleanup extends AsyncTask<Void, Void, Void> { - @Override - protected Void doInBackground(Void... params) { - if (downloadService == null) { - Log.e(TAG, "DownloadService not set. Aborting cache cleaning."); - return null; - } - - 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, getMinimumDelete(files), true); - deleteEmptyDirs(dirs, undeletable); - } catch (RuntimeException x) { - Log.e(TAG, "Error in cache cleaning.", x); - } - - return null; - } - } - - private class BackgroundSpaceCleanup extends AsyncTask<Void, Void, Void> { - @Override - protected Void doInBackground(Void... params) { - if (downloadService == null) { - Log.e(TAG, "DownloadService not set. Aborting cache cleaning."); - return null; - } - - try { - List<File> files = new ArrayList<File>(); - List<File> dirs = new ArrayList<File>(); - findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, dirs); - - long bytesToDelete = getMinimumDelete(files); - if(bytesToDelete > 0L) { - sortByAscendingModificationTime(files); - Set<File> undeletable = findUndeletableFiles(); - deleteFiles(files, undeletable, bytesToDelete, false); - } - } catch (RuntimeException x) { - Log.e(TAG, "Error in cache cleaning.", x); - } - - return null; - } - } - - private class BackgroundPlaylistsCleanup extends AsyncTask<List<Playlist>, Void, Void> { - @Override - protected Void doInBackground(List<Playlist>... params) { - try { - String server = Util.getServerName(context); - SortedSet<File> playlistFiles = FileUtil.listFiles(FileUtil.getPlaylistDirectory(server)); - List<Playlist> playlists = params[0]; - for (Playlist playlist : playlists) { - playlistFiles.remove(FileUtil.getPlaylistFile(server, playlist.getName())); - } - - for(File playlist : playlistFiles) { - playlist.delete(); - } - } catch (RuntimeException x) { - Log.e(TAG, "Error in playlist cache cleaning.", x); - } - - return null; - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/CancellableTask.java b/subsonic-android/src/github/daneren2005/dsub/util/CancellableTask.java deleted file mode 100644 index 933bc0c1..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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.i(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.i(TAG, "Starting thread for " + CancellableTask.this); - try { - execute(); - } finally { - running.set(false); - Log.i(TAG, "Stopping thread for " + CancellableTask.this); - } - } - }); - thread.get().start(); - } - - public static interface OnCancelListener { - void onCancel(); - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java deleted file mode 100644 index 550749b9..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java +++ /dev/null @@ -1,149 +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 github.daneren2005.dsub.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 = "DSub"; - public static final String LAST_VERSION = "subsonic.version"; - - // 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_PARENT_ID = "subsonic.parent_id"; - public static final String INTENT_EXTRA_NAME_PARENT_NAME = "subsonic.parent_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_EXTRA = "subsonic.albumlistextra"; - 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" ; - public static final String INTENT_EXTRA_NAME_DOWNLOAD = "subsonic.download"; - public static final String INTENT_EXTRA_VIEW_ALBUM = "subsonic.view_album"; - public static final String INTENT_EXTRA_NAME_PODCAST_ID = "subsonic.podcast.id"; - public static final String INTENT_EXTRA_NAME_PODCAST_NAME = "subsonic.podcast.name"; - public static final String INTENT_EXTRA_NAME_PODCAST_DESCRIPTION = "subsonic.podcast.description"; - - // 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_KEY = "server"; - public static final String PREFERENCES_KEY_SERVER_COUNT = "serverCount"; - public static final String PREFERENCES_KEY_SERVER_ADD = "serverAdd"; - public static final String PREFERENCES_KEY_SERVER_REMOVE = "serverRemove"; - 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_SERVER_VERSION = "serverVersion"; - public static final String PREFERENCES_KEY_TEST_CONNECTION = "serverTestConnection"; - public static final String PREFERENCES_KEY_OPEN_BROWSER = "openBrowser"; - 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_DISPLAY_TRACK = "displayTrack"; - 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_MAX_VIDEO_BITRATE_WIFI = "maxVideoBitrateWifi"; - public static final String PREFERENCES_KEY_MAX_VIDEO_BITRATE_MOBILE = "maxVideoBitrateMobile"; - public static final String PREFERENCES_KEY_NETWORK_TIMEOUT = "networkTimeout"; - 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_WIFI = "preloadCountWifi"; - public static final String PREFERENCES_KEY_PRELOAD_COUNT_MOBILE = "preloadCountMobile"; - 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"; - public static final String PREFERENCES_KEY_RANDOM_SIZE = "randomSize"; - public static final String PREFERENCES_KEY_SLEEP_TIMER = "sleepTimer"; - public static final String PREFERENCES_KEY_SLEEP_TIMER_DURATION = "sleepTimerDuration"; - public static final String PREFERENCES_KEY_OFFLINE = "offline"; - public static final String PREFERENCES_KEY_TEMP_LOSS = "tempLoss"; - public static final String PREFERENCES_KEY_SHUFFLE_START_YEAR = "startYear"; - public static final String PREFERENCES_KEY_SHUFFLE_END_YEAR = "endYear"; - public static final String PREFERENCES_KEY_SHUFFLE_GENRE = "genre"; - public static final String PREFERENCES_KEY_KEEP_SCREEN_ON = "keepScreenOn"; - public static final String PREFERENCES_KEY_BUFFER_LENGTH = "bufferLength"; - public static final String PREFERENCES_EQUALIZER_ON = "equalizerOn"; - public static final String PREFERENCES_EQUALIZER_SETTINGS = "equalizerSettings"; - public static final String PREFERENCES_KEY_PERSISTENT_NOTIFICATION = "persistentNotification"; - public static final String PREFERENCES_KEY_GAPLESS_PLAYBACK = "gaplessPlayback"; - public static final String PREFERENCES_KEY_SHUFFLE_MODE = "shuffleMode"; - public static final String PREFERENCES_KEY_CHAT_REFRESH = "chatRefreshRate"; - public static final String PREFERENCES_KEY_CHAT_ENABLED = "chatEnabled"; - public static final String PREFERENCES_KEY_VIDEO_PLAYER = "videoPlayer"; - - public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; - public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; - public static final String OFFLINE_SCROBBLE_SEARCH = "scrobbleTitle"; - public static final String OFFLINE_SCROBBLE_TIME = "scrobbleTime"; - public static final String OFFLINE_STAR_COUNT = "starCount"; - public static final String OFFLINE_STAR_ID = "starID"; - public static final String OFFLINE_STAR_SEARCH = "starTitle"; - public static final String OFFLINE_STAR_SETTING = "starSetting"; - - public static final String CACHE_KEY_IGNORE = "ignoreArticles"; - - public static final String MAIN_BACK_STACK = "backStackIds"; - public static final String MAIN_BACK_STACK_SIZE = "backStackIdsSize"; - public static final String MAIN_BACK_STACK_TABS = "backStackTabs"; - public static final String MAIN_BACK_STACK_POSITION = "backStackPosition"; - public static final String FRAGMENT_ID = "fragmentId"; - - // Name of the preferences file. - public static final String PREFERENCES_FILE_NAME = "github.daneren2005.dsub_preferences"; - public static final String OFFLINE_SYNC_NAME = "github.daneren2005.dsub.offline"; - public static final String OFFLINE_SYNC_DEFAULT = "syncDefaults"; - - // 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 = "albumart.jpg"; - - private Constants() { - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java b/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java deleted file mode 100644 index 34bc82bd..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java +++ /dev/null @@ -1,396 +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 github.daneren2005.dsub.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 github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.PodcastEpisode; - -/** - * @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 List<String> VIDEO_FILE_EXTENSIONS = Arrays.asList("flv", "mp4", "m4v", "wmv", "avi", "mov", "mpg", "mkv"); - private static final List<String> PLAYLIST_FILE_EXTENSIONS = Arrays.asList("m3u"); - private static final File DEFAULT_MUSIC_DIR = createDirectory("music"); - - public static File getAnySong(Context context) { - File dir = getMusicDirectory(context); - return getAnySong(context, dir); - } - private static File getAnySong(Context context, File dir) { - for(File file: dir.listFiles()) { - if(file.isDirectory()) { - return getAnySong(context, file); - } - - String extension = getExtension(file.getName()); - if(MUSIC_FILE_EXTENSIONS.contains(extension)) { - return file; - } - } - - return null; - } - - 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 server, String name) { - File playlistDir = getPlaylistDirectory(server); - return new File(playlistDir, fileSystemSafe(name) + ".m3u"); - } - public static File getPlaylistDirectory() { - File playlistDir = new File(getSubsonicDirectory(), "playlists"); - ensureDirectoryExistsAndIsReadWritable(playlistDir); - return playlistDir; - } - public static File getPlaylistDirectory(String server) { - File playlistDir = new File(getPlaylistDirectory(), server); - 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) { - return new File(albumDir, Constants.ALBUM_ART_FILE); - } - - 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 getArtistDirectory(Context context, Artist artist) { - File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getName())); - return dir; - } - public static File getArtistDirectory(Context context, MusicDirectory.Entry artist) { - File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getTitle())); - return dir; - } - - public 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()); - if("unnamed".equals(album)) { - album = fileSystemSafe(entry.getTitle()); - } - dir = new File(getMusicDirectory(context).getPath() + "/" + artist + "/" + album); - } - return dir; - } - - public static String getPodcastPath(Context context, PodcastEpisode episode) { - return fileSystemSafe(episode.getArtist()) + "/" + fileSystemSafe(episode.getTitle()); - } - public static File getPodcastFile(Context context, String server) { - File dir = getPodcastDirectory(context); - return new File(dir.getPath() + "/" + fileSystemSafe(server)); - } - public static File getPodcastDirectory(Context context) { - File dir = new File(getSubsonicDirectory(), "podcasts"); - ensureDirectoryExistsAndIsReadWritable(dir); - return dir; - } - public static File getPodcastDirectory(Context context, PodcastChannel channel) { - File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(channel.getName())); - return dir; - } - public static File getPodcastDirectory(Context context, String channel) { - File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(channel)); - 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 deleteMusicDirectory(Context context) { - File musicDirectory = FileUtil.getMusicDirectory(context); - return Util.recursiveDelete(musicDirectory); - } - - 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> listMediaFiles(File dir) { - SortedSet<File> files = listFiles(dir); - Iterator<File> iterator = files.iterator(); - while (iterator.hasNext()) { - File file = iterator.next(); - if (!file.isDirectory() && !isMediaFile(file)) { - iterator.remove(); - } - } - return files; - } - - private static boolean isMediaFile(File file) { - String extension = getExtension(file.getName()); - return MUSIC_FILE_EXTENSIONS.contains(extension) || VIDEO_FILE_EXTENSIONS.contains(extension); - } - - public static boolean isMusicFile(File file) { - String extension = getExtension(file.getName()); - return MUSIC_FILE_EXTENSIONS.contains(extension); - } - public static boolean isVideoFile(File file) { - String extension = getExtension(file.getName()); - return VIDEO_FILE_EXTENSIONS.contains(extension); - } - - public static boolean isPlaylistFile(File file) { - String extension = getExtension(file.getName()); - return PLAYLIST_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 long getUsedSize(Context context, File file) { - long size = 0L; - - if(file.isFile()) { - return file.length(); - } else { - for (File child : FileUtil.listFiles(file)) { - size += getUsedSize(context, child); - } - return size; - } - } - - 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/github/daneren2005/dsub/util/ImageLoader.java b/subsonic-android/src/github/daneren2005/dsub/util/ImageLoader.java deleted file mode 100644 index 331bc629..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/ImageLoader.java +++ /dev/null @@ -1,332 +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 github.daneren2005.dsub.util; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.TransitionDrawable; -import android.media.RemoteControlClient; -import android.os.Handler; -import android.util.DisplayMetrics; -import android.util.Log; -import android.support.v4.util.LruCache; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.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 - */ -@TargetApi(14) -public class ImageLoader implements Runnable { - - private static final String TAG = ImageLoader.class.getSimpleName(); - private static final int CONCURRENCY = 5; - - private Handler mHandler = new Handler(); - private Context context; - private LruCache<String, Bitmap> cache; - private Bitmap nowPlaying; - private final BlockingQueue<Task> queue; - private final int imageSizeDefault; - private final int imageSizeLarge; - private Drawable largeUnknownImage; - - public ImageLoader(Context context) { - this.context = context; - final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); - final int cacheSize = maxMemory / 4; - cache = new LruCache<String, Bitmap>(cacheSize) { - @Override - protected int sizeOf(String key, Bitmap bitmap) { - return bitmap.getRowBytes() * bitmap.getHeight() / 1024; - } - - @Override - protected void entryRemoved(boolean evicted, String key, Bitmap oldBitmap, Bitmap newBitmap) { - if(evicted && oldBitmap != nowPlaying) { - oldBitmap.recycle(); - } - } - }; - - 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)); - - 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); - largeUnknownImage = Util.createDrawableFromBitmap(context, bitmap); - } - - public void loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) { - if (largeUnknownImage != null && ((BitmapDrawable)largeUnknownImage).getBitmap().isRecycled()) - createLargeUnknownImage(view.getContext()); - - if (entry == null || entry.getCoverArt() == null) { - setUnknownImage(view, large); - return; - } - - int size = large ? imageSizeLarge : imageSizeDefault; - Bitmap bitmap = cache.get(getKey(entry.getCoverArt(), size)); - if (bitmap != null && !bitmap.isRecycled()) { - final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); - setImage(view, drawable, large); - if(large) { - nowPlaying = bitmap; - } - return; - } - - if (!large) { - setUnknownImage(view, large); - } - queue.offer(new Task(view.getContext(), entry, size, imageSizeLarge, large, new ViewTaskHandler(view, crossfade))); - } - - public void loadImage(Context context, RemoteControlClient remoteControl, MusicDirectory.Entry entry) { - if (largeUnknownImage != null && ((BitmapDrawable)largeUnknownImage).getBitmap().isRecycled()) - createLargeUnknownImage(context); - - if (entry == null || entry.getCoverArt() == null) { - setUnknownImage(remoteControl); - return; - } - - Bitmap bitmap = cache.get(getKey(entry.getCoverArt(), imageSizeLarge)); - if (bitmap != null && !bitmap.isRecycled()) { - Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); - setImage(remoteControl, drawable); - return; - } - - setUnknownImage(remoteControl); - queue.offer(new Task(context, entry, imageSizeLarge, imageSizeLarge, false, new RemoteControlClientTaskHandler(remoteControl))); - } - - 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; - if(drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) { - emptyImage = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - } else { - emptyImage = Bitmap.createBitmap(imageSizeDefault, imageSizeDefault, Bitmap.Config.ARGB_8888); - } - existingDrawable = new BitmapDrawable(emptyImage); - } else { - // Try to get rid of old transitions - try { - TransitionDrawable tmp = (TransitionDrawable) existingDrawable; - int layers = tmp.getNumberOfLayers(); - existingDrawable = tmp.getDrawable(layers - 1); - } catch(Exception e) { - // Do nothing, just means that the drawable is a flat image - } - } - if (!(((BitmapDrawable)existingDrawable).getBitmap().isRecycled())) - { // We will flow through to the non-transition if the old image is recycled... Yay 4.3 - Drawable[] layers = new Drawable[]{existingDrawable, drawable}; - - TransitionDrawable transitionDrawable = new TransitionDrawable(layers); - imageView.setImageDrawable(transitionDrawable); - transitionDrawable.startTransition(250); - return; - } - } - imageView.setImageDrawable(drawable); - return; - } - } - - private void setImage(RemoteControlClient remoteControl, Drawable drawable) { - if(remoteControl != null && drawable != null) { - Bitmap origBitmap = ((BitmapDrawable)drawable).getBitmap(); - if ( origBitmap != null && !origBitmap.isRecycled()) { - remoteControl.editMetadata(false) - .putBitmap( - RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, - origBitmap) - .apply(); - } else { - Log.e(TAG, "Tried to load a recycled bitmap."); - remoteControl.editMetadata(false) - .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, null) - .apply(); - } - } - } - - 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); - } - } - } - - private void setUnknownImage(RemoteControlClient remoteControl) { - setImage(remoteControl, largeUnknownImage); - } - - 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 class Task { - private final Context mContext; - private final MusicDirectory.Entry mEntry; - private final int mSize; - private final int mSaveSize; - private final boolean mIsNowPlaying; - private ImageLoaderTaskHandler mTaskHandler; - - public Task(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying, ImageLoaderTaskHandler taskHandler) { - mContext = context; - mEntry = entry; - mSize = size; - mSaveSize = saveSize; - mIsNowPlaying = isNowPlaying; - mTaskHandler = taskHandler; - } - - public void execute() { - try { - loadImage(); - } catch(OutOfMemoryError e) { - Log.w(TAG, "Ran out of memory trying to load image, try cleanup and retry"); - cache.evictAll(); - System.gc(); - } - } - public void loadImage() { - try { - MusicService musicService = MusicServiceFactory.getMusicService(mContext); - Bitmap bitmap = musicService.getCoverArt(mContext, mEntry, mSize, mSaveSize, null); - String key = getKey(mEntry.getCoverArt(), mSize); - cache.put(key, bitmap); - // Make sure key is the most recently "used" - cache.get(key); - if(mIsNowPlaying) { - nowPlaying = bitmap; - } - - final Drawable drawable = Util.createDrawableFromBitmap(mContext, bitmap); - mTaskHandler.setDrawable(drawable); - mHandler.post(mTaskHandler); - } catch (Throwable x) { - Log.e(TAG, "Failed to download album art.", x); - } - } - } - - private abstract class ImageLoaderTaskHandler implements Runnable { - - protected Drawable mDrawable; - - public void setDrawable(Drawable drawable) { - mDrawable = drawable; - } - - } - - private class ViewTaskHandler extends ImageLoaderTaskHandler { - - protected boolean mCrossfade; - private View mView; - - public ViewTaskHandler(View view, boolean crossfade) { - mCrossfade = crossfade; - mView = view; - } - - @Override - public void run() { - setImage(mView, mDrawable, mCrossfade); - } - } - - private class RemoteControlClientTaskHandler extends ImageLoaderTaskHandler { - - private RemoteControlClient mRemoteControl; - - public RemoteControlClientTaskHandler(RemoteControlClient remoteControl) { - mRemoteControl = remoteControl; - } - - @Override - public void run() { - setImage(mRemoteControl, mDrawable); - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java b/subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java deleted file mode 100644 index 9ab5c86d..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java +++ /dev/null @@ -1,97 +0,0 @@ -package github.daneren2005.dsub.util;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-
-import github.daneren2005.dsub.activity.SubsonicActivity;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public abstract class LoadingTask<T> extends BackgroundTask<T> {
-
- private final Activity tabActivity;
- private ProgressDialog loading;
- private Thread thread;
- private final boolean cancellable;
- private boolean cancelled = false;
-
- public LoadingTask(Activity activity) {
- super(activity);
- tabActivity = activity;
- this.cancellable = true;
- }
- public LoadingTask(Activity activity, final boolean cancellable) {
- super(activity);
- tabActivity = activity;
- this.cancellable = cancellable;
- }
-
- @Override
- public void execute() {
- loading = ProgressDialog.show(tabActivity, "", "Loading. Please Wait...", true, cancellable, new DialogInterface.OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- cancel();
- }
-
- });
-
- thread = new Thread() {
- @Override
- public void run() {
- try {
- final T result = doInBackground();
- if (isCancelled()) {
- return;
- }
-
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- loading.cancel();
- done(result);
- }
- });
- } catch (final Throwable t) {
- if (isCancelled()) {
- return;
- }
-
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- loading.cancel();
- error(t);
- }
- });
- }
- }
- };
- thread.start();
- }
-
- protected void cancel() {
- cancelled = true;
- if (thread != null) {
- thread.interrupt();
- }
- }
-
- private boolean isCancelled() {
- return (tabActivity instanceof SubsonicActivity && ((SubsonicActivity)tabActivity).isDestroyed()) || cancelled;
- }
-
- @Override
- public void updateProgress(final String message) {
- if(!cancelled) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- loading.setMessage(message);
- }
- });
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Pair.java b/subsonic-android/src/github/daneren2005/dsub/util/Pair.java deleted file mode 100644 index 54386a62..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/util/ProgressListener.java b/subsonic-android/src/github/daneren2005/dsub/util/ProgressListener.java deleted file mode 100644 index c6d58f42..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.util; - -/** - * @author Sindre Mehus - */ -public interface ProgressListener { - void updateProgress(String message); - void updateProgress(int messageId); -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/SettingsBackupAgent.java b/subsonic-android/src/github/daneren2005/dsub/util/SettingsBackupAgent.java deleted file mode 100644 index 7eb6d137..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/SettingsBackupAgent.java +++ /dev/null @@ -1,31 +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 github.daneren2005.dsub.util; - -import android.app.backup.BackupAgentHelper; -import android.app.backup.SharedPreferencesBackupHelper; -import github.daneren2005.dsub.util.Constants; - -public class SettingsBackupAgent extends BackupAgentHelper { - public void onCreate() { - super.onCreate(); - SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Constants.PREFERENCES_FILE_NAME); - addHelper("mypreferences", helper); - } - } diff --git a/subsonic-android/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java b/subsonic-android/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java deleted file mode 100644 index 195fe913..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java +++ /dev/null @@ -1,127 +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 github.daneren2005.dsub.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.content.SharedPreferences; -import android.util.Log; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.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 int lastCount = -1; - private Context context; - private int currentServer; - private String currentFolder = ""; - - private String genre = ""; - private String startYear = ""; - private String endYear = ""; - - 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)) || lastCount == 0) { - return; - } - - try { - MusicService service = MusicServiceFactory.getMusicService(context); - int n = CAPACITY - buffer.size(); - String folder = Util.getSelectedMusicFolderId(context); - MusicDirectory songs = service.getRandomSongs(n, folder, genre, startYear, endYear, context, null); - - synchronized (buffer) { - buffer.addAll(songs.getChildren()); - Log.i(TAG, "Refilled shuffle play buffer with " + songs.getChildrenSize() + " songs."); - lastCount = songs.getChildrenSize(); - } - } catch (Exception x) { - Log.w(TAG, "Failed to refill shuffle play buffer.", x); - } - } - - private void clearBufferIfnecessary() { - synchronized (buffer) { - final SharedPreferences prefs = Util.getPreferences(context); - if (currentServer != Util.getActiveServer(context) - || (currentFolder != null && !currentFolder.equals(Util.getSelectedMusicFolderId(context))) - || (genre != null && !genre.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, ""))) - || (startYear != null && !startYear.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, ""))) - || (endYear != null && !endYear.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "")))) { - lastCount = -1; - currentServer = Util.getActiveServer(context); - currentFolder = Util.getSelectedMusicFolderId(context); - genre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, ""); - startYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, ""); - endYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, ""); - buffer.clear(); - } - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/SilentBackgroundTask.java b/subsonic-android/src/github/daneren2005/dsub/util/SilentBackgroundTask.java deleted file mode 100644 index 7bceb467..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/util/SimpleServiceBinder.java b/subsonic-android/src/github/daneren2005/dsub/util/SimpleServiceBinder.java deleted file mode 100644 index 9c0b36a9..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/util/TabBackgroundTask.java b/subsonic-android/src/github/daneren2005/dsub/util/TabBackgroundTask.java deleted file mode 100644 index c345b982..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/TabBackgroundTask.java +++ /dev/null @@ -1,67 +0,0 @@ -package github.daneren2005.dsub.util;
-
-import github.daneren2005.dsub.fragments.SubsonicFragment;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public abstract class TabBackgroundTask<T> extends BackgroundTask<T> {
-
- private final SubsonicFragment tabFragment;
-
- public TabBackgroundTask(SubsonicFragment fragment) {
- super(fragment.getActivity());
- tabFragment = fragment;
- }
-
- @Override
- public void execute() {
- tabFragment.setProgressVisible(true);
-
- new Thread() {
- @Override
- public void run() {
- try {
- final T result = doInBackground();
- if (isCancelled()) {
- return;
- }
-
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabFragment.setProgressVisible(false);
- done(result);
- }
- });
- } catch (final Throwable t) {
- if (isCancelled()) {
- return;
- }
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabFragment.setProgressVisible(false);
- error(t);
- }
- });
- }
- }
- }.start();
- }
-
- private boolean isCancelled() {
- return !tabFragment.isAdded();
- }
-
- @Override
- public void updateProgress(final String message) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabFragment.updateProgress(message);
- }
- });
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/TimeLimitedCache.java b/subsonic-android/src/github/daneren2005/dsub/util/TimeLimitedCache.java deleted file mode 100644 index 8b7df783..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/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 github.daneren2005.dsub.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/github/daneren2005/dsub/util/Util.java b/subsonic-android/src/github/daneren2005/dsub/util/Util.java deleted file mode 100644 index a6fdd987..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/Util.java +++ /dev/null @@ -1,1173 +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 github.daneren2005.dsub.util; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Notification; -import android.app.PendingIntent; -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.media.AudioManager.OnAudioFocusChangeListener; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.wifi.WifiManager; -import android.os.Build; -import android.os.Environment; -import android.os.Handler; -import android.support.v4.app.NotificationCompat; -import android.text.SpannableString; -import android.text.method.LinkMovementMethod; -import android.text.util.Linkify; -import android.util.Log; -import android.view.Gravity; -import android.view.ViewGroup; -import android.view.KeyEvent; -import android.widget.LinearLayout; -import android.widget.RemoteViews; -import android.widget.TextView; -import android.widget.Toast; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.MainActivity; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.RepeatMode; -import github.daneren2005.dsub.domain.Version; -import github.daneren2005.dsub.provider.DSubWidgetProvider; -import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.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 = "github.daneren2005.dsub.EVENT_META_CHANGED"; - public static final String EVENT_PLAYSTATE_CHANGED = "github.daneren2005.dsub.EVENT_PLAYSTATE_CHANGED"; - - public static final String AVRCP_PLAYSTATE_CHANGED = "com.android.music.playstatechanged"; - public static final String AVRCP_METADATA_CHANGED = "com.android.music.metachanged"; - - private static boolean hasFocus = false; - private static boolean pauseFocus = false; - private static boolean lowerFocus = false; - - 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) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_OFFLINE, false); - } - - public static void setOffline(Context context, boolean offline) { - SharedPreferences prefs = getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, offline); - editor.commit(); - } - - 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) { - 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.putString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, null); - editor.commit(); - } - - public static int getActiveServer(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - } - - public static boolean checkServerVersion(Context context, String requiredVersion) { - Version version = Util.getServerRestVersion(context); - Version required = new Version(requiredVersion); - if(version != null && version.compareTo(required) >= 0) { - return true; - } else { - return false; - } - } - - public static int getServerCount(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 1); - } - - public static void removeInstanceName(Context context, int instance, int activeInstance) { - SharedPreferences prefs = getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - - int newInstance = instance + 1; - - String server = prefs.getString(Constants.PREFERENCES_KEY_SERVER_KEY + newInstance, null); - String serverName = prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + newInstance, null); - String serverUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + newInstance, null); - String userName = prefs.getString(Constants.PREFERENCES_KEY_USERNAME + newInstance, null); - String password = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + newInstance, null); - - editor.putString(Constants.PREFERENCES_KEY_SERVER_KEY + instance, server); - editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, serverName); - editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + instance, serverUrl); - editor.putString(Constants.PREFERENCES_KEY_USERNAME + instance, userName); - editor.putString(Constants.PREFERENCES_KEY_PASSWORD + instance, password); - - editor.putString(Constants.PREFERENCES_KEY_SERVER_KEY + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_USERNAME + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_PASSWORD + newInstance, null); - editor.commit(); - - if (instance == activeInstance) { - if(instance != 1) { - Util.setActiveServer(context, 1); - } else { - Util.setOffline(context, true); - } - } else if (newInstance == activeInstance) { - Util.setActiveServer(context, instance); - } - } - - public static String getServerName(Context context) { - SharedPreferences prefs = getPreferences(context); - int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null); - } - public static String getServerName(Context context, int instance) { - SharedPreferences prefs = getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null); - } - - public static String getUserName(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_USERNAME + instance, null); - } - - public static void setServerRestVersion(Context context, Version version) { - int instance = getActiveServer(context); - Version current = SERVER_REST_VERSIONS.get(instance); - if(current != version) { - SERVER_REST_VERSIONS.put(instance, version); - SharedPreferences.Editor editor = getPreferences(context).edit(); - editor.putString(Constants.PREFERENCES_KEY_SERVER_VERSION + instance, version.getVersion()); - editor.commit(); - } - } - - public static Version getServerRestVersion(Context context) { - int instance = getActiveServer(context); - Version version = SERVER_REST_VERSIONS.get(instance); - if(version == null) { - SharedPreferences prefs = getPreferences(context); - String versionString = prefs.getString(Constants.PREFERENCES_KEY_SERVER_VERSION + instance, null); - if(versionString != null) { - version = new Version(versionString); - SERVER_REST_VERSIONS.put(instance, version); - } - } - return version; - } - - 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 boolean getDisplayTrack(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_DISPLAY_TRACK, false); - } - - 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 getMaxVideoBitrate(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_VIDEO_BITRATE_WIFI : Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_MOBILE, "0")); - } - - public static int getPreloadCount(Context context) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - if (networkInfo == null) { - return 3; - } - - SharedPreferences prefs = getPreferences(context); - boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI; - int preloadCount = Integer.parseInt(prefs.getString(wifi ? Constants.PREFERENCES_KEY_PRELOAD_COUNT_WIFI : Constants.PREFERENCES_KEY_PRELOAD_COUNT_MOBILE, "-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 String getVideoPlayerType(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_VIDEO_PLAYER, "raw"); - } - - public static SharedPreferences getPreferences(Context context) { - return context.getSharedPreferences(Constants.PREFERENCES_FILE_NAME, 0); - } - public static SharedPreferences getOfflineSync(Context context) { - return context.getSharedPreferences(Constants.OFFLINE_SYNC_NAME, 0); - } - - public static String getSyncDefault(Context context) { - SharedPreferences prefs = Util.getOfflineSync(context); - return prefs.getString(Constants.OFFLINE_SYNC_DEFAULT, null); - } - public static void setSyncDefault(Context context, String defaultValue) { - SharedPreferences.Editor editor = Util.getOfflineSync(context).edit(); - editor.putString(Constants.OFFLINE_SYNC_DEFAULT, defaultValue); - editor.commit(); - } - - public static int offlineScrobblesCount(Context context) { - SharedPreferences offline = getOfflineSync(context); - return offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - } - public static int offlineStarsCount(Context context) { - SharedPreferences offline = getOfflineSync(context); - return offline.getInt(Constants.OFFLINE_STAR_COUNT, 0); - } - - public static String parseOfflineIDSearch(Context context, String id, String cacheLocation) { - String name = id.replace(cacheLocation, ""); - if(name.startsWith("/")) { - name = name.substring(1); - } - name = name.replace(".complete", "").replace(".partial", ""); - int index = name.lastIndexOf("."); - name = index == -1 ? name : name.substring(0, index); - String[] details = name.split("/"); - - String title = details[details.length - 1]; - if(index == -1) { - if(details.length > 1) { - String artist = "artist:\"" + details[details.length - 2] + "\""; - String simpleArtist = "artist:\"" + title + "\""; - title = "album:\"" + title + "\""; - if(details[details.length - 1].equals(details[details.length - 2])) { - name = title; - } else { - name = "(" + artist + " AND " + title + ")" + " OR " + simpleArtist; - } - } else { - name = "artist:\"" + title + "\" OR album:\"" + title + "\""; - } - } else { - String artist; - if(details.length > 2) { - artist = "artist:\"" + details[details.length - 3] + "\""; - } else { - artist = "(artist:\"" + details[0] + "\" OR album:\"" + details[0] + "\")"; - } - title = "title:\"" + title.substring(title.indexOf('-') + 1) + "\""; - name = artist + " AND " + title; - } - - return name; - } - - 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 renameFile(File from, File to) throws IOException { - if(from.renameTo(to)) { - Log.i(TAG, "Renamed " + from + " to " + to); - } else { - atomicCopy(from, to); - } - } - - 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 boolean recursiveDelete(File dir) { - if (dir != null && dir.exists()) { - for(File file: dir.listFiles()) { - if(file.isDirectory()) { - if(!recursiveDelete(file)) { - return false; - } - } else if(file.exists()) { - if(!file.delete()) { - return false; - } - } - } - return dir.delete(); - } - return false; - } - - 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(); - } - - public static void confirmDialog(Context context, int action, String subject, DialogInterface.OnClickListener onClick) { - Util.confirmDialog(context, context.getResources().getString(action).toLowerCase(), subject, onClick); - } - public static void confirmDialog(Context context, String action, String subject, DialogInterface.OnClickListener onClick) { - new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.common_confirm) - .setMessage(context.getResources().getString(R.string.common_confirm_message, action, subject)) - .setPositiveButton(R.string.common_ok, onClick) - .setNegativeButton(R.string.common_cancel, null) - .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 hours = seconds / 3600; - int minutes = (seconds / 60) % 60; - int secs = seconds % 60; - - StringBuilder builder = new StringBuilder(7); - if(hours > 0) { - builder.append(hours).append(":"); - if(minutes < 10) { - builder.append("0"); - } - } - 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 isNullOrWhiteSpace(String string) { - return string == null || string.isEmpty() || string.trim().isEmpty(); - } - - 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); - } - public static void info(Context context, int titleId, String message) { - showDialog(context, android.R.drawable.ic_dialog_info, titleId, message); - } - public static void info(Context context, String title, String message) { - showDialog(context, android.R.drawable.ic_dialog_info, title, message); - } - - private static void showDialog(Context context, int icon, int titleId, int messageId) { - showDialog(context, icon, context.getResources().getString(titleId), context.getResources().getString(messageId)); - } - private static void showDialog(Context context, int icon, int titleId, String message) { - showDialog(context, icon, context.getResources().getString(titleId), message); - } - private static void showDialog(Context context, int icon, String title, String message) { - SpannableString ss = new SpannableString(message); - Linkify.addLinks(ss, Linkify.ALL); - - AlertDialog dialog = new AlertDialog.Builder(context) - .setIcon(icon) - .setTitle(title) - .setMessage(ss) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int i) { - dialog.dismiss(); - } - }) - .show(); - - ((TextView)dialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); - } - - public static void showPlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler, MusicDirectory.Entry song) { - // Set the icon, scrolling text and timestamp - final Notification notification = new Notification(R.drawable.stat_notify_playing, song.getTitle(), System.currentTimeMillis()); - notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; - - boolean playing = downloadService.getPlayerState() == PlayerState.STARTED; - if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){ - RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded); - setupViews(expandedContentView,context,song, playing); - notification.bigContentView = expandedContentView; - } - - RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification); - setupViews(smallContentView, context, song, playing); - notification.contentView = smallContentView; - - Intent notificationIntent = new Intent(context, MainActivity.class); - notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true); - notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - notification.contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0); - - handler.post(new Runnable() { - @Override - public void run() { - downloadService.startForeground(Constants.NOTIFICATION_ID_PLAYING, notification); - } - }); - - // Update widget - DSubWidgetProvider.notifyInstances(context, downloadService, true); - } - - private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean playing){ - - // Use the same text for the ticker and the expanded notification - String title = song.getTitle(); - String arist = song.getArtist(); - String album = song.getAlbum(); - - // 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 - rv.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); - } else { - rv.setImageViewBitmap(R.id.notification_image, bitmap); - } - } catch (Exception x) { - Log.w(TAG, "Failed to get notification cover art", x); - rv.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); - } - - // set the text for the notifications - rv.setTextViewText(R.id.notification_title, title); - rv.setTextViewText(R.id.notification_artist, arist); - rv.setTextViewText(R.id.notification_album, album); - - Pair<Integer, Integer> colors = getNotificationTextColors(context); - if (colors.getFirst() != null) { - rv.setTextColor(R.id.notification_title, colors.getFirst()); - } - if (colors.getSecond() != null) { - rv.setTextColor(R.id.notification_artist, colors.getSecond()); - } - - if(!playing) { - rv.setImageViewResource(R.id.control_pause, R.drawable.notification_play); - rv.setImageViewResource(R.id.control_previous, R.drawable.notification_stop); - } - - // Create actions for media buttons - PendingIntent pendingIntent; - if(playing) { - Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS"); - prevIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class)); - prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS)); - pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0); - rv.setOnClickPendingIntent(R.id.control_previous, pendingIntent); - } else { - Intent prevIntent = new Intent("KEYCODE_MEDIA_STOP"); - prevIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class)); - prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP)); - pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0); - rv.setOnClickPendingIntent(R.id.control_previous, pendingIntent); - } - - Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE"); - pauseIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class)); - pauseIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)); - pendingIntent = PendingIntent.getService(context, 0, pauseIntent, 0); - rv.setOnClickPendingIntent(R.id.control_pause, pendingIntent); - - Intent nextIntent = new Intent("KEYCODE_MEDIA_NEXT"); - nextIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class)); - nextIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT)); - pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0); - rv.setOnClickPendingIntent(R.id.control_next, pendingIntent); - } - - 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() { - downloadService.stopForeground(true); - } - }); - - // Update widget - DSubWidgetProvider.notifyInstances(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. - } - } - - @TargetApi(8) - public static void requestAudioFocus(final Context context) { - if (Build.VERSION.SDK_INT >= 8 && !hasFocus) { - final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - hasFocus = true; - audioManager.requestAudioFocus(new OnAudioFocusChangeListener() { - public void onAudioFocusChange(int focusChange) { - DownloadServiceImpl downloadService = (DownloadServiceImpl)context; - if((focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) && !downloadService.isJukeboxEnabled()) { - if(downloadService.getPlayerState() == PlayerState.STARTED) { - SharedPreferences prefs = getPreferences(context); - int lossPref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")); - if(lossPref == 2 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)) { - lowerFocus = true; - downloadService.setVolume(0.1f); - } else if(lossPref == 0 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)) { - pauseFocus = true; - downloadService.pause(); - } - } - } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { - if(pauseFocus) { - pauseFocus = false; - downloadService.start(); - } else if(lowerFocus) { - lowerFocus = false; - downloadService.setVolume(1.0f); - } - } else if(focusChange == AudioManager.AUDIOFOCUS_LOSS && !downloadService.isJukeboxEnabled()) { - hasFocus = false; - downloadService.pause(); - audioManager.abandonAudioFocus(this); - } - } - }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); - } - } - - /** - * <p>Broadcasts the given song info as the new song being played.</p> - */ - public static void broadcastNewTrackInfo(Context context, MusicDirectory.Entry song) { - DownloadService downloadService = (DownloadServiceImpl)context; - Intent intent = new Intent(EVENT_META_CHANGED); - Intent avrcpIntent = new Intent(AVRCP_METADATA_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()); - - avrcpIntent.putExtra("playing", true); - avrcpIntent.putExtra("track", song.getTitle()); - avrcpIntent.putExtra("artist", song.getArtist()); - avrcpIntent.putExtra("album", song.getAlbum()); - avrcpIntent.putExtra("ListSize",(long) downloadService.getSongs().size()); - avrcpIntent.putExtra("id", (long) downloadService.getCurrentPlayingIndex()+1); - avrcpIntent.putExtra("duration", (long) downloadService.getPlayerDuration()); - avrcpIntent.putExtra("position", (long) downloadService.getPlayerPosition()); - avrcpIntent.putExtra("coverart", albumArtFile.getAbsolutePath()); - } else { - intent.putExtra("title", ""); - intent.putExtra("artist", ""); - intent.putExtra("album", ""); - intent.putExtra("coverart", ""); - - avrcpIntent.putExtra("playing", false); - avrcpIntent.putExtra("track", ""); - avrcpIntent.putExtra("artist", ""); - avrcpIntent.putExtra("album", ""); - avrcpIntent.putExtra("ListSize",(long)0); - avrcpIntent.putExtra("id", (long) 0); - avrcpIntent.putExtra("duration", (long )0); - avrcpIntent.putExtra("position", (long) 0); - avrcpIntent.putExtra("coverart", ""); - } - - context.sendBroadcast(intent); - context.sendBroadcast(avrcpIntent); - } - - /** - * <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); - Intent avrcpIntent = new Intent(AVRCP_PLAYSTATE_CHANGED); - - switch (state) { - case STARTED: - intent.putExtra("state", "play"); - avrcpIntent.putExtra("playing", true); - break; - case STOPPED: - intent.putExtra("state", "stop"); - avrcpIntent.putExtra("playing", false); - break; - case PAUSED: - intent.putExtra("state", "pause"); - avrcpIntent.putExtra("playing", false); - break; - case COMPLETED: - intent.putExtra("state", "complete"); - avrcpIntent.putExtra("playing", false); - break; - default: - return; // No need to broadcast. - } - - context.sendBroadcast(intent); - context.sendBroadcast(avrcpIntent); - } - - /** - * 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); - } - } - - public static WifiManager.WifiLock createWifiLock(Context context, String tag) { - WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - int lockType = WifiManager.WIFI_MODE_FULL; - if (Build.VERSION.SDK_INT >= 12) { - lockType = 3; - } - return wm.createWifiLock(lockType, tag); - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java deleted file mode 100644 index c3f3f70c..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java +++ /dev/null @@ -1,32 +0,0 @@ -package github.daneren2005.dsub.util.compat; - -import github.daneren2005.dsub.domain.MusicDirectory.Entry; -import android.content.ComponentName; -import android.content.Context; -import android.util.Log; - -public class RemoteControlClientBase extends RemoteControlClientHelper { - - private static final String TAG = RemoteControlClientBase.class.getSimpleName(); - - @Override - public void register(Context context, ComponentName mediaButtonReceiverComponent) { - Log.w(TAG, "RemoteControlClient requires Android API level 14 or higher."); - } - - @Override - public void unregister(Context context) { - Log.w(TAG, "RemoteControlClient requires Android API level 14 or higher."); - } - - @Override - public void setPlaybackState(int state) { - Log.w(TAG, "RemoteControlClient requires Android API level 14 or higher."); - } - - @Override - public void updateMetadata(Context context, Entry currentSong) { - Log.w(TAG, "RemoteControlClient requires Android API level 14 or higher."); - } - -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java deleted file mode 100644 index ddaa9f43..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java +++ /dev/null @@ -1,27 +0,0 @@ -package github.daneren2005.dsub.util.compat; - -import github.daneren2005.dsub.domain.MusicDirectory; -import android.content.ComponentName; -import android.content.Context; -import android.os.Build; - -public abstract class RemoteControlClientHelper { - - public static RemoteControlClientHelper createInstance() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - return new RemoteControlClientBase(); - } else { - return new RemoteControlClientICS(); - } - } - - protected RemoteControlClientHelper() { - // Avoid instantiation - } - - public abstract void register(final Context context, final ComponentName mediaButtonReceiverComponent); - public abstract void unregister(final Context context); - public abstract void setPlaybackState(final int state); - public abstract void updateMetadata(final Context context, final MusicDirectory.Entry currentSong); - -} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java deleted file mode 100644 index a8fed63d..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java +++ /dev/null @@ -1,79 +0,0 @@ -package github.daneren2005.dsub.util.compat; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.media.AudioManager; -import android.media.MediaMetadataRetriever; -import android.media.RemoteControlClient; -import github.daneren2005.dsub.activity.SubsonicActivity; - -@TargetApi(14) -public class RemoteControlClientICS extends RemoteControlClientHelper { - - private RemoteControlClient mRemoteControl; - private ImageLoader imageLoader; - - public void register(final Context context, final ComponentName mediaButtonReceiverComponent) { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - - // build the PendingIntent for the remote control client - Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); - mediaButtonIntent.setComponent(mediaButtonReceiverComponent); - PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, mediaButtonIntent, 0); - - // create and register the remote control client - mRemoteControl = new RemoteControlClient(mediaPendingIntent); - audioManager.registerRemoteControlClient(mRemoteControl); - - mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); - - mRemoteControl.setTransportControlFlags( - RemoteControlClient.FLAG_KEY_MEDIA_PLAY | - RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | - RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | - RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | - RemoteControlClient.FLAG_KEY_MEDIA_NEXT | - RemoteControlClient.FLAG_KEY_MEDIA_STOP); - - imageLoader = SubsonicActivity.getStaticImageLoader(context); - } - - public void unregister(final Context context) { - if (mRemoteControl != null) { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - audioManager.unregisterRemoteControlClient(mRemoteControl); - } - } - - public void setPlaybackState(final int state) { - mRemoteControl.setPlaybackState(state); - } - - public void updateMetadata(final Context context, final MusicDirectory.Entry currentSong) { - if(imageLoader == null) { - imageLoader = SubsonicActivity.getStaticImageLoader(context); - } - - // Update the remote controls - mRemoteControl.editMetadata(true) - .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, (currentSong == null) ? null : currentSong.getArtist()) - .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, (currentSong == null) ? null : currentSong.getArtist()) - .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, (currentSong) == null ? null : currentSong.getTitle()) - .putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, (currentSong == null) ? - 0 : ((currentSong.getDuration() == null) ? 0 : currentSong.getDuration())) - .apply(); - if (currentSong == null || imageLoader == null) { - mRemoteControl.editMetadata(true) - .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, null) - .apply(); - } else { - imageLoader.loadImage(context, mRemoteControl, currentSong); - } - } - -} diff --git a/subsonic-android/src/github/daneren2005/dsub/view/AlbumListAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/AlbumListAdapter.java deleted file mode 100644 index 3ff8350b..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/AlbumListAdapter.java +++ /dev/null @@ -1,83 +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 github.daneren2005.dsub.view;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import com.commonsware.cwac.endless.EndlessAdapter;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import java.util.List;
-
-public class AlbumListAdapter extends EndlessAdapter {
- Context context;
- ArrayAdapter<MusicDirectory.Entry> adapter;
- String type;
- String extra;
- int size;
- int offset;
- List<MusicDirectory.Entry> entries;
-
- public AlbumListAdapter(Context context, ArrayAdapter<MusicDirectory.Entry> adapter, String type, String extra, int size) {
- super(adapter);
- this.context = context;
- this.adapter = adapter;
- this.type = type;
- this.extra = extra;
- this.size = size;
- this.offset = size;
- }
-
- @Override
- protected boolean cacheInBackground() throws Exception {
- MusicService service = MusicServiceFactory.getMusicService(context);
- MusicDirectory result;
- if("genres".equals(type)) {
- result = service.getSongsByGenre(extra, size, offset, context, null);
- } else {
- result = service.getAlbumList(type, size, offset, context, null);
- }
- entries = result.getChildren();
- if(entries.size() > 0) {
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- protected void appendCachedData() {
- for(MusicDirectory.Entry entry: entries) {
- adapter.add(entry);
- }
- offset += entries.size();
- }
-
- @Override
- protected View getPendingView(ViewGroup parent) {
- View progress = LayoutInflater.from(context).inflate(R.layout.tab_progress, null);
- progress.setVisibility(View.VISIBLE);
- return progress;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/AlbumView.java b/subsonic-android/src/github/daneren2005/dsub/view/AlbumView.java deleted file mode 100644 index 3a7b895e..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/AlbumView.java +++ /dev/null @@ -1,93 +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 github.daneren2005.dsub.view; - -import android.content.Context; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.Util; -import java.io.File; -/** - * Used to display albums in a {@code ListView}. - * - * @author Sindre Mehus - */ -public class AlbumView extends UpdateView { - private static final String TAG = AlbumView.class.getSimpleName(); - - private Context context; - private MusicDirectory.Entry album; - - private TextView titleView; - private TextView artistView; - private View coverArtView; - private ImageButton starButton; - private ImageView moreButton; - - public AlbumView(Context context) { - super(context); - this.context = 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); - starButton = (ImageButton) findViewById(R.id.album_star); - - moreButton = (ImageView) findViewById(R.id.album_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - public void setAlbum(MusicDirectory.Entry album, ImageLoader imageLoader) { - this.album = album; - - titleView.setText(album.getTitle()); - artistView.setText(album.getArtist()); - artistView.setVisibility(album.getArtist() == null ? View.GONE : View.VISIBLE); - imageLoader.loadImage(coverArtView, album, false, true); - - starButton.setVisibility(!album.isStarred() ? View.GONE : View.VISIBLE); - starButton.setFocusable(false); - - update(); - } - - @Override - protected void update() { - starButton.setVisibility(!album.isStarred() ? View.GONE : View.VISIBLE); - File file = FileUtil.getAlbumDirectory(context, album); - if(file.exists()) { - moreButton.setImageResource(R.drawable.list_item_more_shaded); - } else { - moreButton.setImageResource(R.drawable.list_item_more); - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java deleted file mode 100644 index 7e9bf218..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java +++ /dev/null @@ -1,95 +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 github.daneren2005.dsub.view; - -import android.content.Context; -import github.daneren2005.dsub.R; -import java.util.List; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; -import github.daneren2005.dsub.domain.Artist; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * @author Sindre Mehus - */ -public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexer { - - private final Context activity; - - // Both arrays are indexed by section ID. - private final Object[] sections; - private final Integer[] positions; - - public ArtistAdapter(Context activity, List<Artist> artists) { - super(activity, R.layout.artist_list_item, artists); - this.activity = activity; - - 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 View getView(int position, View convertView, ViewGroup parent) { - Artist entry = getItem(position); - ArtistView view; - if (convertView != null && convertView instanceof ArtistView) { - view = (ArtistView) convertView; - } else { - view = new ArtistView(activity); - } - view.setArtist(entry); - return view; - } - - @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/github/daneren2005/dsub/view/ArtistEntryView.java b/subsonic-android/src/github/daneren2005/dsub/view/ArtistEntryView.java deleted file mode 100644 index 3b6a50e4..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/ArtistEntryView.java +++ /dev/null @@ -1,83 +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 github.daneren2005.dsub.view;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.ImageLoader;
-import github.daneren2005.dsub.util.Util;
-import java.io.File;
-/**
- * Used to display albums in a {@code ListView}.
- *
- * @author Sindre Mehus
- */
-public class ArtistEntryView extends UpdateView {
- private static final String TAG = AlbumView.class.getSimpleName();
-
- private Context context;
- private MusicDirectory.Entry artist;
-
- private TextView titleView;
- private ImageButton starButton;
- private ImageView moreButton;
-
- public ArtistEntryView(Context context) {
- super(context);
- this.context = context;
- LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
-
- titleView = (TextView) findViewById(R.id.artist_name);
- starButton = (ImageButton) findViewById(R.id.artist_star);
- moreButton = (ImageView) findViewById(R.id.artist_more);
- moreButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- v.showContextMenu();
- }
- });
- }
-
- public void setArtist(MusicDirectory.Entry artist) {
- this.artist = artist;
-
- titleView.setText(artist.getTitle());
- starButton.setVisibility((Util.isOffline(getContext()) || !artist.isStarred()) ? View.GONE : View.VISIBLE);
- starButton.setFocusable(false);
- update();
- }
-
- @Override
- protected void update() {
- starButton.setVisibility((Util.isOffline(getContext()) || !artist.isStarred()) ? View.GONE : View.VISIBLE);
- File file = FileUtil.getArtistDirectory(context, artist);
- if(file.exists()) {
- moreButton.setImageResource(R.drawable.list_item_more_shaded);
- } else {
- moreButton.setImageResource(R.drawable.list_item_more);
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/ArtistView.java b/subsonic-android/src/github/daneren2005/dsub/view/ArtistView.java deleted file mode 100644 index 353be618..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/ArtistView.java +++ /dev/null @@ -1,84 +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 github.daneren2005.dsub.view;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Artist;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.Util;
-import java.io.File;
-
-/**
- * Used to display albums in a {@code ListView}.
- *
- * @author Sindre Mehus
- */
-public class ArtistView extends UpdateView {
- private static final String TAG = ArtistView.class.getSimpleName();
-
- private Context context;
- private Artist artist;
-
- private TextView titleView;
- private ImageButton starButton;
- private ImageView moreButton;
-
- public ArtistView(Context context) {
- super(context);
- this.context = context;
- LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
-
- titleView = (TextView) findViewById(R.id.artist_name);
- starButton = (ImageButton) findViewById(R.id.artist_star);
- moreButton = (ImageView) findViewById(R.id.artist_more);
- moreButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- v.showContextMenu();
- }
- });
- }
-
- public void setArtist(Artist artist) {
- this.artist = artist;
-
- titleView.setText(artist.getName());
-
- starButton.setVisibility((Util.isOffline(getContext()) || !artist.isStarred()) ? View.GONE : View.VISIBLE);
- starButton.setFocusable(false);
-
- update();
- }
-
- @Override
- protected void update() {
- starButton.setVisibility((Util.isOffline(getContext()) || !artist.isStarred()) ? View.GONE : View.VISIBLE);
- File file = FileUtil.getArtistDirectory(context, artist);
- if(file.exists()) {
- moreButton.setImageResource(R.drawable.list_item_more_shaded);
- } else {
- moreButton.setImageResource(R.drawable.list_item_more);
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/AutoRepeatButton.java b/subsonic-android/src/github/daneren2005/dsub/view/AutoRepeatButton.java deleted file mode 100644 index 798c1649..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/AutoRepeatButton.java +++ /dev/null @@ -1,86 +0,0 @@ -package github.daneren2005.dsub.view;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageButton;
-
-public class AutoRepeatButton extends ImageButton {
-
- private long initialRepeatDelay = 1000;
- private long repeatIntervalInMilliseconds = 300;
- private boolean doClick = true;
- private Runnable repeatEvent = null;
-
- private Runnable repeatClickWhileButtonHeldRunnable = new Runnable() {
- @Override
- public void run() {
- doClick = false;
- //Perform the present repetition of the click action provided by the user
- // in setOnClickListener().
- if(repeatEvent != null)
- repeatEvent.run();
-
- //Schedule the next repetitions of the click action, using a faster repeat
- // interval than the initial repeat delay interval.
- postDelayed(repeatClickWhileButtonHeldRunnable, repeatIntervalInMilliseconds);
- }
- };
-
- private void commonConstructorCode() {
- this.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- int action = event.getAction();
- if(action == MotionEvent.ACTION_DOWN)
- {
- doClick = true;
- //Just to be sure that we removed all callbacks,
- // which should have occurred in the ACTION_UP
- removeCallbacks(repeatClickWhileButtonHeldRunnable);
-
- //Schedule the start of repetitions after a one half second delay.
- postDelayed(repeatClickWhileButtonHeldRunnable, initialRepeatDelay);
-
- setPressed(true);
- }
- else if(action == MotionEvent.ACTION_UP) {
- //Cancel any repetition in progress.
- removeCallbacks(repeatClickWhileButtonHeldRunnable);
-
- if(doClick || repeatEvent == null) {
- performClick();
- }
-
- setPressed(false);
- }
-
- //Returning true here prevents performClick() from getting called
- // in the usual manner, which would be redundant, given that we are
- // already calling it above.
- return true;
- }
- });
- }
-
- public void setOnRepeatListener(Runnable runnable) {
- repeatEvent = runnable;
- }
-
- public AutoRepeatButton(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- commonConstructorCode();
- }
-
-
- public AutoRepeatButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- commonConstructorCode();
- }
-
- public AutoRepeatButton(Context context) {
- super(context);
- commonConstructorCode();
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/ChangeLog.java b/subsonic-android/src/github/daneren2005/dsub/view/ChangeLog.java deleted file mode 100644 index b847733e..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/ChangeLog.java +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Copyright (C) 2012 Christian Ketterer (cketti) - * - * Portions Copyright (C) 2012 Martin van Zuilekom (http://martin.cubeactive.com) - * - * 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. - * - * - * Based on android-change-log: - * - * Copyright (C) 2011, Karsten Priegnitz - * - * Permission to use, copy, modify, and distribute this piece of software - * for any purpose with or without fee is hereby granted, provided that - * the above copyright notice and this permission notice appear in the - * source code of all copies. - * - * It would be appreciated if you mention the author in your change log, - * contributors list or the like. - * - * http://code.google.com/p/android-change-log/ - */ -package github.daneren2005.dsub.view; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.content.res.XmlResourceParser; -import android.preference.PreferenceManager; -import android.util.Log; -import android.util.SparseArray; -import android.webkit.WebView; -import github.daneren2005.dsub.R; - - -/** - * Display a dialog showing a full or partial (What's New) change log. - */ -public class ChangeLog { - /** - * Tag that is used when sending error/debug messages to the log. - */ - protected static final String LOG_TAG = "ckChangeLog"; - - /** - * This is the key used when storing the version code in SharedPreferences. - */ - protected static final String VERSION_KEY = "ckChangeLog_last_version_code"; - - /** - * Constant that used when no version code is available. - */ - protected static final int NO_VERSION = -1; - - /** - * Default CSS styles used to format the change log. - */ - private static final String DEFAULT_CSS = - "div.title { margin-left: 0px; font-size: 1.2em; text-align: center;}" + - "div.subtitle {margin-left: 0px; font-size: .8em; text-align: center;}" + - "li { margin-left: 0px;}" + - "ul { padding-left: 2em;}"; - - - /** - * Context that is used to access the resources and to create the ChangeLog dialogs. - */ - protected final Context mContext; - - /** - * Contains the CSS rules used to format the change log. - */ - protected final String mCss; - - /** - * Last version code read from {@code SharedPreferences} or {@link #NO_VERSION}. - */ - private int mLastVersionCode; - - /** - * Version code of the current installation. - */ - private int mCurrentVersionCode; - - /** - * Version name of the current installation. - */ - private String mCurrentVersionName; - - - /** - * Contains constants for the root element of {@code changelog.xml}. - */ - protected interface ChangeLogTag { - static final String NAME = "changelog"; - } - - /** - * Contains constants for the release element of {@code changelog.xml}. - */ - protected interface ReleaseTag { - static final String NAME = "release"; - static final String ATTRIBUTE_VERSION = "version"; - static final String ATTRIBUTE_VERSION_CODE = "versioncode"; - static final String ATTRIBUTE_RELEASE_DATE = "releasedate"; - } - - /** - * Contains constants for the change element of {@code changelog.xml}. - */ - protected interface ChangeTag { - static final String NAME = "change"; - } - - /** - * Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file. - * - * @param context - * Context that is used to access the resources and to create the ChangeLog dialogs. - */ - public ChangeLog(Context context) { - this(context, PreferenceManager.getDefaultSharedPreferences(context), DEFAULT_CSS); - } - - /** - * Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file. - * - * @param context - * Context that is used to access the resources and to create the ChangeLog dialogs. - * @param css - * CSS styles that will be used to format the change log. - */ - public ChangeLog(Context context, String css) { - this(context, PreferenceManager.getDefaultSharedPreferences(context), css); - } - - public ChangeLog(Context context, SharedPreferences preferences) { - this(context, preferences, DEFAULT_CSS); - } - - /** - * Create a {@code ChangeLog} instance using the supplied {@code SharedPreferences} instance. - * - * @param context - * Context that is used to access the resources and to create the ChangeLog dialogs. - * @param preferences - * {@code SharedPreferences} instance that is used to persist the last version code. - * @param css - * CSS styles used to format the change log (excluding {@code <style>} and - * {@code </style>}). - * - */ - public ChangeLog(Context context, SharedPreferences preferences, String css) { - mContext = context; - mCss = css; - - // Get last version code - mLastVersionCode = preferences.getInt(VERSION_KEY, NO_VERSION); - - // Get current version code and version name - try { - PackageInfo packageInfo = context.getPackageManager().getPackageInfo( - context.getPackageName(), 0); - - mCurrentVersionCode = packageInfo.versionCode; - mCurrentVersionName = packageInfo.versionName; - } catch (NameNotFoundException e) { - mCurrentVersionCode = NO_VERSION; - Log.e(LOG_TAG, "Could not get version information from manifest!", e); - } - } - - /** - * Get version code of last installation. - * - * @return The version code of the last installation of this app (as described in the former - * manifest). This will be the same as returned by {@link #getCurrentVersionCode()} the - * second time this version of the app is launched (more precisely: the second time - * {@code ChangeLog} is instantiated). - * - * @see AndroidManifest.xml#android:versionCode - */ - public int getLastVersionCode() { - return mLastVersionCode; - } - - /** - * Get version code of current installation. - * - * @return The version code of this app as described in the manifest. - * - * @see AndroidManifest.xml#android:versionCode - */ - public int getCurrentVersionCode() { - return mCurrentVersionCode; - } - - /** - * Get version name of current installation. - * - * @return The version name of this app as described in the manifest. - * - * @see AndroidManifest.xml#android:versionName - */ - public String getCurrentVersionName() { - return mCurrentVersionName; - } - - /** - * Check if this is the first execution of this app version. - * - * @return {@code true} if this version of your app is started the first time. - */ - public boolean isFirstRun() { - return mLastVersionCode < mCurrentVersionCode; - } - - /** - * Check if this is a new installation. - * - * @return {@code true} if your app including {@code ChangeLog} is started the first time ever. - * Also {@code true} if your app was uninstalled and installed again. - */ - public boolean isFirstRunEver() { - return mLastVersionCode == NO_VERSION; - } - - /** - * Get the "What's New" dialog. - * - * @return An AlertDialog displaying the changes since the previous installed version of your - * app (What's New). But when this is the first run of your app including - * {@code ChangeLog} then the full log dialog is show. - */ - public AlertDialog getLogDialog() { - return getDialog(isFirstRunEver()); - } - - /** - * Get a dialog with the full change log. - * - * @return An AlertDialog with a full change log displayed. - */ - public AlertDialog getFullLogDialog() { - return getDialog(true); - } - - /** - * Create a dialog containing (parts of the) change log. - * - * @param full - * If this is {@code true} the full change log is displayed. Otherwise only changes for - * versions newer than the last version are displayed. - * - * @return A dialog containing the (partial) change log. - */ - protected AlertDialog getDialog(boolean full) { - WebView wv = new WebView(mContext); - //wv.setBackgroundColor(0); // transparent - wv.loadDataWithBaseURL(null, getLog(full), "text/html", "UTF-8", null); - - AlertDialog.Builder builder = new AlertDialog.Builder(mContext); - builder.setTitle( - mContext.getResources().getString( - full ? R.string.changelog_full_title : R.string.changelog_title)) - .setView(wv) - .setCancelable(false) - // OK button - .setPositiveButton( - mContext.getResources().getString(R.string.changelog_ok_button), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // The user clicked "OK" so save the current version code as - // "last version code". - updateVersionInPreferences(); - } - }); - - if (!full) { - // Show "More…" button if we're only displaying a partial change log. - builder.setNegativeButton(R.string.changelog_show_full, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - getFullLogDialog().show(); - } - }); - } - - return builder.create(); - } - - /** - * Write current version code to the preferences. - */ - protected void updateVersionInPreferences() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - SharedPreferences.Editor editor = sp.edit(); - editor.putInt(VERSION_KEY, mCurrentVersionCode); - - // TODO: Update preferences from a background thread - editor.commit(); - } - - /** - * Get changes since last version as HTML string. - * - * @return HTML string containing the changes since the previous installed version of your app - * (What's New). - */ - public String getLog() { - return getLog(false); - } - - /** - * Get full change log as HTML string. - * - * @return HTML string containing the full change log. - */ - public String getFullLog() { - return getLog(true); - } - - /** - * Get (partial) change log as HTML string. - * - * @param full - * If this is {@code true} the full change log is returned. Otherwise only changes for - * versions newer than the last version are returned. - * - * @return The (partial) change log. - */ - private String getLog(boolean full) { - StringBuilder sb = new StringBuilder(); - - sb.append("<html><head><style type=\"text/css\">"); - sb.append(mCss); - sb.append("</style></head><body>"); - - Resources resources = mContext.getResources(); - - // Read master change log from raw/changelog.xml - SparseArray<ReleaseItem> defaultChangelog; - try { - XmlPullParser xml = XmlPullParserFactory.newInstance().newPullParser(); - InputStreamReader reader = new InputStreamReader(resources.openRawResource(R.raw.changelog)); - xml.setInput(reader); - try { - defaultChangelog = readChangeLog(xml, full); - } finally { - try { reader.close(); } catch (Exception e) { /* do nothing */ } - } - } catch (XmlPullParserException e) { - Log.e(LOG_TAG, "Error reading raw/changelog.xml", e); - return null; - } - - // Read localized change log from xml[-lang]/changelog.xml - XmlResourceParser resXml = mContext.getResources().getXml(R.xml.changelog); - SparseArray<ReleaseItem> changelog; - try { - changelog = readChangeLog(resXml, full); - } finally { - resXml.close(); - } - - String versionFormat = resources.getString(R.string.changelog_version_format); - - // Get all version codes from the master change log... - List<Integer> versions = new ArrayList<Integer>(defaultChangelog.size()); - for (int i = 0, len = defaultChangelog.size(); i < len; i++) { - int key = defaultChangelog.keyAt(i); - versions.add(key); - } - - // ... and sort them (newest version first). - Collections.sort(versions, Collections.reverseOrder()); - - for (Integer version : versions) { - int key = version.intValue(); - - // Use release information from localized change log and fall back to the master file - // if necessary. - ReleaseItem release = changelog.get(key, defaultChangelog.get(key)); - - sb.append("<div class='title'>"); - sb.append(String.format(versionFormat, release.versionName)); - sb.append("</div>"); - if(release.releaseDate != null) { - sb.append("<div class='subtitle'>"); - sb.append(release.releaseDate); - sb.append("</div>"); - } - sb.append("<ul>"); - for (String change : release.changes) { - sb.append("<li>"); - sb.append(change); - sb.append("</li>"); - } - sb.append("</ul>"); - } - - sb.append("</body></html>"); - - return sb.toString(); - } - - /** - * Read the change log from an XML file. - * - * @param xml - * The {@code XmlPullParser} instance used to read the change log. - * @param full - * If {@code true} the full change log is read. Otherwise only the changes since the - * last (saved) version are read. - * - * @return A {@code SparseArray} mapping the version codes to release information. - */ - protected SparseArray<ReleaseItem> readChangeLog(XmlPullParser xml, boolean full) { - SparseArray<ReleaseItem> result = new SparseArray<ReleaseItem>(); - - try { - int eventType = xml.getEventType(); - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ReleaseTag.NAME)) { - if (parseReleaseTag(xml, full, result)) { - // Stop reading more elements if this entry is not newer than the last - // version. - break; - } - } - eventType = xml.next(); - } - } catch (XmlPullParserException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } catch (IOException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - - return result; - } - - /** - * Parse the {@code release} tag of a change log XML file. - * - * @param xml - * The {@code XmlPullParser} instance used to read the change log. - * @param full - * If {@code true} the contents of the {@code release} tag are always added to - * {@code changelog}. Otherwise only if the item's {@code versioncode} attribute is - * higher than the last version code. - * @param changelog - * The {@code SparseArray} to add a new {@link ReleaseItem} instance to. - * - * @return {@code true} if the {@code release} element is describing changes of a version older - * or equal to the last version. In that case {@code changelog} won't be modified and - * {@link #readChangeLog(XmlPullParser, boolean)} will stop reading more elements from - * the change log file. - * - * @throws XmlPullParserException - * @throws IOException - */ - private boolean parseReleaseTag(XmlPullParser xml, boolean full, - SparseArray<ReleaseItem> changelog) throws XmlPullParserException, IOException { - - String version = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION); - - int versionCode; - try { - String versionCodeStr = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION_CODE); - versionCode = Integer.parseInt(versionCodeStr); - } catch (NumberFormatException e) { - versionCode = NO_VERSION; - } - - String releaseDate = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_RELEASE_DATE); - - if (!full && versionCode <= mLastVersionCode) { - return true; - } - - int eventType = xml.getEventType(); - List<String> changes = new ArrayList<String>(); - while (eventType != XmlPullParser.END_TAG || xml.getName().equals(ChangeTag.NAME)) { - if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ChangeTag.NAME)) { - eventType = xml.next(); - - changes.add(xml.getText()); - } - eventType = xml.next(); - } - - ReleaseItem release = new ReleaseItem(versionCode, version, releaseDate, changes); - changelog.put(versionCode, release); - - return false; - } - - /** - * Container used to store information about a release/version. - */ - protected static class ReleaseItem { - /** - * Version code of the release. - */ - public final int versionCode; - - /** - * Version name of the release. - */ - public final String versionName; - - public final String releaseDate; - - /** - * List of changes introduced with that release. - */ - public final List<String> changes; - - ReleaseItem(int versionCode, String versionName, String releaseDate, List<String> changes) { - this.versionCode = versionCode; - this.versionName = versionName; - this.releaseDate = releaseDate; - this.changes = changes; - } - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/view/ChatAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/ChatAdapter.java deleted file mode 100644 index 518f81ef..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/ChatAdapter.java +++ /dev/null @@ -1,100 +0,0 @@ -package github.daneren2005.dsub.view;
-
-import android.text.method.LinkMovementMethod;
-import android.text.util.Linkify;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.activity.SubsonicActivity;
-import github.daneren2005.dsub.domain.ChatMessage;
-import github.daneren2005.dsub.util.Util;
-
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.regex.Pattern;
-
-public class ChatAdapter extends ArrayAdapter<ChatMessage> {
-
- private final SubsonicActivity activity;
- private ArrayList<ChatMessage> messages;
-
- private static final String phoneRegex = "1?\\W*([2-9][0-8][0-9])\\W*([2-9][0-9]{2})\\W*([0-9]{4})"; //you can just place your support phone here
- private static final Pattern phoneMatcher = Pattern.compile(phoneRegex);
-
- public ChatAdapter(SubsonicActivity activity, ArrayList<ChatMessage> messages) {
- super(activity, R.layout.chat_item, messages);
- this.activity = activity;
- this.messages = messages;
- }
-
- @Override
- public int getCount() {
- return messages.size();
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ChatMessage message = this.getItem(position);
-
- ViewHolder holder;
- int layout;
-
- String messageUser = message.getUsername();
- Date messageTime = new java.util.Date(message.getTime());
- String messageText = message.getMessage();
-
- String me = Util.getUserName(activity, Util.getActiveServer(activity));
-
- if (messageUser.equals(me)) {
- layout = R.layout.chat_item_reverse;
- } else {
- layout = R.layout.chat_item;
- }
-
- if (convertView == null)
- {
- holder = new ViewHolder();
-
- convertView = LayoutInflater.from(activity).inflate(layout, parent, false);
-
- TextView usernameView = (TextView) convertView.findViewById(R.id.chat_username);
- TextView timeView = (TextView) convertView.findViewById(R.id.chat_time);
- TextView messageView = (TextView) convertView.findViewById(R.id.chat_message);
-
- messageView.setMovementMethod(LinkMovementMethod.getInstance());
- Linkify.addLinks(messageView, Linkify.EMAIL_ADDRESSES);
- Linkify.addLinks(messageView, Linkify.WEB_URLS);
- Linkify.addLinks(messageView, phoneMatcher, "tel:");
-
- holder.message = messageView;
- holder.username = usernameView;
- holder.time = timeView;
-
- convertView.setTag(holder);
- }
- else
- {
- holder = (ViewHolder) convertView.getTag();
- }
-
- DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(activity);
- String messageTimeFormatted = String.format("[%s]", timeFormat.format(messageTime));
-
- holder.username.setText(messageUser);
- holder.message.setText(messageText);
- holder.time.setText(messageTimeFormatted);
-
- return convertView;
- }
-
- private static class ViewHolder
- {
- TextView message;
- TextView username;
- TextView time;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/EntryAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/EntryAdapter.java deleted file mode 100644 index ff7393c6..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/EntryAdapter.java +++ /dev/null @@ -1,79 +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 github.daneren2005.dsub.view; - -import android.content.Context; -import android.util.Log; -import java.util.List; - -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; - -/** - * @author Sindre Mehus - */ -public class EntryAdapter extends ArrayAdapter<MusicDirectory.Entry> { - private final static String TAG = EntryAdapter.class.getSimpleName(); - private final Context activity; - private final ImageLoader imageLoader; - private final boolean checkable; - private List<MusicDirectory.Entry> entries; - - public EntryAdapter(Context activity, ImageLoader imageLoader, List<MusicDirectory.Entry> entries, boolean checkable) { - super(activity, android.R.layout.simple_list_item_1, entries); - this.entries = entries; - this.activity = activity; - this.imageLoader = imageLoader; - this.checkable = checkable; - } - - public void removeAt(int position) { - entries.remove(position); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - MusicDirectory.Entry entry = getItem(position); - - if (entry.isDirectory()) { - if(entry.getArtist() != null || entry.getParent() != null) { - AlbumView view; - view = new AlbumView(activity); - view.setAlbum(entry, imageLoader); - return view; - } else { - ArtistEntryView view = new ArtistEntryView(activity); - view.setArtist(entry); - 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/github/daneren2005/dsub/view/ErrorDialog.java b/subsonic-android/src/github/daneren2005/dsub/view/ErrorDialog.java deleted file mode 100644 index e9f25a2d..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/ErrorDialog.java +++ /dev/null @@ -1,70 +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 github.daneren2005.dsub.view; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import github.daneren2005.dsub.activity.MainActivity; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.util.Util; - -/** - * @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) { - restart(activity); - } - } - }); - builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (finishActivityOnClose) { - restart(activity); - } - } - }); - - builder.create().show(); - } - - private void restart(Activity context) { - Intent intent = new Intent(context, MainActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(context, intent); - } -} diff --git a/subsonic-android/src/github/daneren2005/dsub/view/FadeOutAnimation.java b/subsonic-android/src/github/daneren2005/dsub/view/FadeOutAnimation.java deleted file mode 100644 index 292529e6..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/FadeOutAnimation.java +++ /dev/null @@ -1,77 +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 github.daneren2005.dsub.view;
-
-import android.view.View;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-
-/**
- * Fades a view out by changing its alpha value.
- *
- * @author Sindre Mehus
- * @version $Id: Util.java 3203 2012-10-04 09:12:08Z sindre_mehus $
- */
-public class FadeOutAnimation extends AlphaAnimation {
-
- private boolean cancelled;
-
- /**
- * Creates and starts the fade out animation.
- *
- * @param view The view to fade out (or display).
- * @param fadeOut If true, the view is faded out. Otherwise it is immediately made visible.
- * @param durationMillis Fade duration.
- */
- public static void createAndStart(View view, boolean fadeOut, long durationMillis) {
- if (fadeOut) {
- view.clearAnimation();
- view.startAnimation(new FadeOutAnimation(view, durationMillis));
- } else {
- Animation animation = view.getAnimation();
- if (animation instanceof FadeOutAnimation) {
- ((FadeOutAnimation) animation).cancelFadeOut();
- }
- view.clearAnimation();
- view.setVisibility(View.VISIBLE);
- }
- }
-
- FadeOutAnimation(final View view, long durationMillis) {
- super(1.0F, 0.0F);
- setDuration(durationMillis);
- setAnimationListener(new AnimationListener() {
- public void onAnimationStart(Animation animation) {
- }
-
- public void onAnimationRepeat(Animation animation) {
- }
-
- public void onAnimationEnd(Animation animation) {
- if (!cancelled) {
- view.setVisibility(View.INVISIBLE);
- }
- }
- });
- }
-
- private void cancelFadeOut() {
- cancelled = true;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/GenreAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/GenreAdapter.java deleted file mode 100644 index b98efd20..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/GenreAdapter.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 2010 (C) Sindre Mehus
- */
-package github.daneren2005.dsub.view;
-
-import android.widget.ArrayAdapter;
-import android.widget.SectionIndexer;
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Genre;
-
-import java.util.List;
-import java.util.Set;
-import java.util.LinkedHashSet;
-import java.util.ArrayList;
-
-/**
- * @author Sindre Mehus
-*/
-public class GenreAdapter extends ArrayAdapter<Genre>{
- private Context activity;
- private List<Genre> genres;
-
- public GenreAdapter(Context context, List<Genre> genres) {
- super(context, android.R.layout.simple_list_item_1, genres);
- this.activity = context;
- this.genres = genres;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Genre genre = genres.get(position);
- GenreView view;
- if (convertView != null && convertView instanceof GenreView) {
- view = (GenreView) convertView;
- } else {
- view = new GenreView(activity);
- }
- view.setGenre(genre);
- return view;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/GenreView.java b/subsonic-android/src/github/daneren2005/dsub/view/GenreView.java deleted file mode 100644 index dbb0248b..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/GenreView.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 github.daneren2005.dsub.view;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Genre;
-
-public class GenreView extends UpdateView {
- private static final String TAG = GenreView.class.getSimpleName();
-
- private TextView titleView;
- private ImageButton starButton;
- private ImageView moreButton;
-
- public GenreView(Context context) {
- super(context);
- LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
-
- titleView = (TextView) findViewById(R.id.artist_name);
- starButton = (ImageButton) findViewById(R.id.artist_star);
- moreButton = (ImageView) findViewById(R.id.artist_more);
- moreButton.setClickable(false);
- }
-
- public void setGenre(Genre genre) {
- titleView.setText(genre.getName());
-
- starButton.setVisibility(View.GONE);
- starButton.setFocusable(false);
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/MergeAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/MergeAdapter.java deleted file mode 100644 index bfe777ea..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/MergeAdapter.java +++ /dev/null @@ -1,292 +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 github.daneren2005.dsub.view; - -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; - -import github.daneren2005.dsub.view.SackOfViewsAdapter; - -/** - * 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/github/daneren2005/dsub/view/MyViewFlipper.java b/subsonic-android/src/github/daneren2005/dsub/view/MyViewFlipper.java deleted file mode 100644 index 26a3de08..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/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 github.daneren2005.dsub.view; - -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/github/daneren2005/dsub/view/PlaylistAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/PlaylistAdapter.java deleted file mode 100644 index 71727c04..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/PlaylistAdapter.java +++ /dev/null @@ -1,68 +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 github.daneren2005.dsub.view; - -import android.content.Context; -import github.daneren2005.dsub.R; -import java.util.List; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import github.daneren2005.dsub.domain.Playlist; -import java.util.Collections; -import java.util.Comparator; - -/** - * @author Sindre Mehus - */ -public class PlaylistAdapter extends ArrayAdapter<Playlist> { - - private final Context activity; - - public PlaylistAdapter(Context activity, List<Playlist> Playlists) { - super(activity, R.layout.playlist_list_item, Playlists); - this.activity = activity; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Playlist entry = getItem(position); - PlaylistView view; - if (convertView != null && convertView instanceof PlaylistView) { - view = (PlaylistView) convertView; - } else { - view = new PlaylistView(activity); - } - view.setPlaylist(entry); - return view; - } - - 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/github/daneren2005/dsub/view/PlaylistView.java b/subsonic-android/src/github/daneren2005/dsub/view/PlaylistView.java deleted file mode 100644 index 876e0691..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/PlaylistView.java +++ /dev/null @@ -1,76 +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 github.daneren2005.dsub.view;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Playlist;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.Util;
-import java.io.File;
-
-/**
- * Used to display albums in a {@code ListView}.
- *
- * @author Sindre Mehus
- */
-public class PlaylistView extends UpdateView {
- private static final String TAG = PlaylistView.class.getSimpleName();
-
- private Context context;
- private Playlist playlist;
-
- private TextView titleView;
- private ImageView moreButton;
-
- public PlaylistView(Context context) {
- super(context);
- this.context = context;
- LayoutInflater.from(context).inflate(R.layout.playlist_list_item, this, true);
-
- titleView = (TextView) findViewById(R.id.playlist_name);
- moreButton = (ImageView) findViewById(R.id.playlist_more);
- moreButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- v.showContextMenu();
- }
- });
- }
-
- public void setPlaylist(Playlist playlist) {
- this.playlist = playlist;
-
- titleView.setText(playlist.getName());
- update();
- }
-
- @Override
- protected void update() {
- File file = FileUtil.getPlaylistFile(Util.getServerName(context), playlist.getName());
- if(file.exists() || Util.isOffline(context)) {
- moreButton.setImageResource(R.drawable.list_item_more_shaded);
- } else {
- moreButton.setImageResource(R.drawable.list_item_more);
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java deleted file mode 100644 index 6b7af991..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.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 2010 (C) Sindre Mehus
- */
-package github.daneren2005.dsub.view;
-
-import android.widget.ArrayAdapter;
-import android.widget.SectionIndexer;
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.PodcastChannel;
-
-import java.util.List;
-import java.util.Set;
-import java.util.LinkedHashSet;
-import java.util.ArrayList;
-
-/**
- * @author Sindre Mehus
-*/
-public class PodcastChannelAdapter extends ArrayAdapter<PodcastChannel>{
- private Context activity;
- private List<PodcastChannel> podcasts;
-
- public PodcastChannelAdapter(Context context, List<PodcastChannel> podcasts) {
- super(context, android.R.layout.simple_list_item_1, podcasts);
- this.activity = context;
- this.podcasts = podcasts;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- PodcastChannel podcast = podcasts.get(position);
- PodcastChannelView view;
- if (convertView != null && convertView instanceof PodcastChannelView) {
- view = (PodcastChannelView) convertView;
- } else {
- view = new PodcastChannelView(activity);
- }
- view.setPodcastChannel(podcast);
- return view;
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java deleted file mode 100644 index 94eedf2c..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java +++ /dev/null @@ -1,76 +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 github.daneren2005.dsub.view;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.PodcastChannel;
-import github.daneren2005.dsub.util.FileUtil;
-import java.io.File;
-
-public class PodcastChannelView extends UpdateView {
- private static final String TAG = PodcastChannelView.class.getSimpleName();
-
- private Context context;
- private PodcastChannel channel;
-
- private TextView titleView;
- private ImageView moreButton;
-
- public PodcastChannelView(Context context) {
- super(context);
- this.context = context;
- LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
-
- titleView = (TextView) findViewById(R.id.artist_name);
- ImageButton starButton = (ImageButton) findViewById(R.id.artist_star);
- starButton.setVisibility(View.GONE);
- starButton.setFocusable(false);
- moreButton = (ImageView) findViewById(R.id.artist_more);
- moreButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- v.showContextMenu();
- }
- });
- }
-
- public void setPodcastChannel(PodcastChannel podcastChannel) {
- channel = podcastChannel;
- if(podcastChannel.getName() != null) {
- titleView.setText(podcastChannel.getName());
- } else {
- titleView.setText(podcastChannel.getUrl());
- }
- }
-
- @Override
- protected void update() {
- File file = FileUtil.getPodcastDirectory(context, channel);
- if(file.exists()) {
- moreButton.setImageResource(R.drawable.list_item_more_shaded);
- } else {
- moreButton.setImageResource(R.drawable.list_item_more);
- }
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/SackOfViewsAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/SackOfViewsAdapter.java deleted file mode 100644 index ff2280c1..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/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 github.daneren2005.dsub.view; - -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/github/daneren2005/dsub/view/SongView.java b/subsonic-android/src/github/daneren2005/dsub/view/SongView.java deleted file mode 100644 index 042d8031..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/SongView.java +++ /dev/null @@ -1,241 +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 github.daneren2005.dsub.view; - -import android.content.Context; -import android.media.MediaMetadataRetriever; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.*; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.DownloadServiceImpl; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.util.Util; - -import java.io.File; -import java.text.DateFormat; - -/** - * Used to display songs in a {@code ListView}. - * - * @author Sindre Mehus - */ -public class SongView extends UpdateView implements Checkable { - private static final String TAG = SongView.class.getSimpleName(); - - private Context context; - private MusicDirectory.Entry song; - - private CheckedTextView checkedTextView; - private TextView titleTextView; - private TextView artistTextView; - private TextView durationTextView; - private TextView statusTextView; - private ImageButton starButton; - private ImageView moreButton; - - private DownloadService downloadService; - private long revision = -1; - private DownloadFile downloadFile; - - private boolean playing = false; - private int rightImage = 0; - private int moreImage = 0; - private boolean starred = false; - private boolean isWorkDone = false; - private boolean isSaved = false; - private File partialFile; - private boolean partialFileExists = false; - - public SongView(Context context) { - super(context); - this.context = 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); - starButton = (ImageButton) findViewById(R.id.song_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.artist_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - 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(); - } - - if(!song.isVideo()) { - if(song instanceof PodcastEpisode) { - String date = ((PodcastEpisode)song).getDate(); - if(date != null) { - int index = date.indexOf(" "); - artist.append(date.substring(0, index != -1 ? index : date.length())); - } - } - else if(song.getArtist() != null) { - artist.append(song.getArtist()); - } - - String status = (song instanceof PodcastEpisode) ? ((PodcastEpisode)song).getStatus() : ""; - artist.append(" ("); - if("error".equals(status)) { - artist.append(getContext().getString(R.string.song_details_error)); - } else if("skipped".equals(status)) { - artist.append(getContext().getString(R.string.song_details_skipped)); - } else if("downloading".equals(status)) { - artist.append(getContext().getString(R.string.song_details_downloading)); - } else { - artist.append(String.format(getContext().getString(R.string.song_details_all), bitRate == null ? "" : bitRate, fileFormat)); - } - artist.append(")"); - } else { - artist.append(String.format(getContext().getString(R.string.song_details_all), bitRate == null ? "" : bitRate, fileFormat)); - } - - String title = song.getTitle(); - Integer track = song.getTrack(); - if(track != null && Util.getDisplayTrack(context)) { - title = String.format("%02d", track) + " " + title; - } - - titleTextView.setText(title); - artistTextView.setText(artist); - durationTextView.setText(Util.formatDuration(song.getDuration())); - checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE); - - revision = -1; - updateBackground(); - update(); - } - - @Override - protected void updateBackground() { - if (downloadService == null) { - downloadService = DownloadServiceImpl.getInstance(); - if(downloadService == null) { - return; - } - } - - long newRevision = downloadService.getDownloadListUpdateRevision(); - if(revision != newRevision || downloadFile == null) { - downloadFile = downloadService.forSong(song); - revision = newRevision; - } - - isWorkDone = downloadFile.isWorkDone(); - isSaved = downloadFile.isSaved(); - partialFile = downloadFile.getPartialFile(); - partialFileExists = partialFile.exists(); - } - - @Override - protected void update() { - if (downloadService == null) { - return; - } - - if(song.isStarred()) { - if(!starred) { - starButton.setVisibility(View.VISIBLE); - starred = true; - } - } else { - if(starred) { - starButton.setVisibility(View.GONE); - starred = false; - } - } - - int rightImage = 0; - if (isWorkDone) { - int moreImage = isSaved ? R.drawable.list_item_more_saved : R.drawable.list_item_more_shaded; - if(moreImage != this.moreImage) { - moreButton.setImageResource(moreImage); - this.moreImage = moreImage; - } - } else if(this.moreImage != R.drawable.list_item_more) { - moreButton.setImageResource(R.drawable.list_item_more); - this.moreImage = R.drawable.list_item_more; - } - - if (downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && partialFileExists) { - statusTextView.setText(Util.formatLocalizedBytes(partialFile.length(), getContext())); - rightImage = R.drawable.downloading; - } else if(this.rightImage != 0) { - statusTextView.setText(null); - } - if(this.rightImage != rightImage) { - statusTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, rightImage, 0); - this.rightImage = rightImage; - } - - boolean playing = downloadService.getCurrentPlaying() == downloadFile; - if (playing) { - if(!this.playing) { - this.playing = playing; - titleTextView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.stat_notify_playing, 0, 0, 0); - } - } else { - if(this.playing) { - this.playing = playing; - titleTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); - } - } - } - - @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/github/daneren2005/dsub/view/UpdateView.java b/subsonic-android/src/github/daneren2005/dsub/view/UpdateView.java deleted file mode 100644 index 7ce27f06..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/UpdateView.java +++ /dev/null @@ -1,133 +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 github.daneren2005.dsub.view;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.LinearLayout;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.WeakHashMap;
-
-public class UpdateView extends LinearLayout {
- private static final String TAG = UpdateView.class.getSimpleName();
- private static final WeakHashMap<UpdateView, ?> INSTANCES = new WeakHashMap<UpdateView, Object>();
-
- private static Handler backgroundHandler;
- private static Handler uiHandler;
- private static Runnable updateRunnable;
-
- public UpdateView(Context context) {
- super(context);
-
- setLayoutParams(new AbsListView.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
-
- INSTANCES.put(this, null);
- int instanceCount = INSTANCES.size();
- if (instanceCount > 50) {
- Log.w(TAG, instanceCount + " live UpdateView instances");
- }
-
- startUpdater();
- }
-
- @Override
- public void setPressed(boolean pressed) {
-
- }
-
- private static synchronized void startUpdater() {
- if(uiHandler != null) {
- return;
- }
-
- uiHandler = new Handler();
- updateRunnable = new Runnable() {
- @Override
- public void run() {
- updateAll();
- }
- };
-
- new Thread(new Runnable() {
- public void run() {
- Looper.prepare();
- backgroundHandler = new Handler(Looper.myLooper());
- uiHandler.post(updateRunnable);
- Looper.loop();
- }
- }).start();
- }
-
- private static void updateAll() {
- try {
- List<UpdateView> views = new ArrayList<UpdateView>();;
- for (UpdateView view : INSTANCES.keySet()) {
- if (view.isShown()) {
- views.add(view);
- }
- }
- updateAllLive(views);
- } catch (Throwable x) {
- Log.w(TAG, "Error when updating song views.", x);
- }
- }
- private static void updateAllLive(final List<UpdateView> views) {
- final Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- for(UpdateView view: views) {
- view.update();
- }
- } catch (Throwable x) {
- Log.w(TAG, "Error when updating song views.", x);
- }
- uiHandler.postDelayed(updateRunnable, 1000L);
- }
- };
-
- backgroundHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- for(UpdateView view: views) {
- view.updateBackground();
- }
- uiHandler.post(runnable);
- } catch (Throwable x) {
- Log.w(TAG, "Error when updating song views.", x);
- }
- }
- });
- }
-
- protected void updateBackground() {
-
- }
- protected void update() {
-
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/VisualizerView.java b/subsonic-android/src/github/daneren2005/dsub/view/VisualizerView.java deleted file mode 100644 index 53ebc2ec..00000000 --- a/subsonic-android/src/github/daneren2005/dsub/view/VisualizerView.java +++ /dev/null @@ -1,137 +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 github.daneren2005.dsub.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 github.daneren2005.dsub.audiofx.VisualizerController; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.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 = false; - - public VisualizerView(Context context) { - super(context); - - paint.setStrokeWidth(2f); - paint.setAntiAlias(true); - paint.setColor(Color.rgb(51, 181, 229)); - } - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - VisualizerController visualizerController = getVizualiser(); - Visualizer visualizer = visualizerController == null ? null : visualizerController.getVisualizer(); - if (visualizer == null) { - this.active = false; - 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); - if(!active) { - visualizerController.release(); - } - invalidate(); - } - - private VisualizerController getVizualiser() { - DownloadService downloadService = DownloadServiceImpl.getInstance(); - VisualizerController visualizerController = downloadService == null ? null : downloadService.getVisualizerController(); - return visualizerController; - } - - 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); - } -} |