aboutsummaryrefslogtreecommitdiff
path: root/subsonic-android
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2013-03-03 21:26:52 -0800
committerScott Jackson <daneren2005@gmail.com>2013-03-03 21:26:52 -0800
commita31c08a45adc84e9b6b7954f91eaa3d049964c45 (patch)
tree67e5c70430a64418954e19a19ec721780fc39e83 /subsonic-android
parent8d6d21840f1eaa29018b4e3c0940b68d113b8f7f (diff)
downloaddsub-a31c08a45adc84e9b6b7954f91eaa3d049964c45.tar.gz
dsub-a31c08a45adc84e9b6b7954f91eaa3d049964c45.tar.bz2
dsub-a31c08a45adc84e9b6b7954f91eaa3d049964c45.zip
Start converting activities to fragments
Diffstat (limited to 'subsonic-android')
-rw-r--r--subsonic-android/AndroidManifest.xml2
-rw-r--r--subsonic-android/res/layout/music.xml25
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/MusicActivity.java146
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java194
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java124
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicTabFragment.java95
6 files changed, 585 insertions, 1 deletions
diff --git a/subsonic-android/AndroidManifest.xml b/subsonic-android/AndroidManifest.xml
index b8513db8..d50083fa 100644
--- a/subsonic-android/AndroidManifest.xml
+++ b/subsonic-android/AndroidManifest.xml
@@ -22,7 +22,7 @@
<application android:label="@string/common.appname" android:icon="@drawable/launch2" android:theme="@style/Theme.DSub.Holo">
- <activity android:name="github.daneren2005.dsub.activity.MainActivity"
+ <activity android:name="github.daneren2005.dsub.activity.MusicActivity"
android:label="DSub"
android:configChanges="orientation|keyboardHidden"
android:launchMode="standard">
diff --git a/subsonic-android/res/layout/music.xml b/subsonic-android/res/layout/music.xml
new file mode 100644
index 00000000..f5c95b3f
--- /dev/null
+++ b/subsonic-android/res/layout/music.xml
@@ -0,0 +1,25 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical" >
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" >
+
+ <!-- Optional page title view -->
+
+ <android.support.v4.view.PagerTitleStrip
+ android:id="@+id/pager_title_strip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:background="#33b5e5"
+ android:paddingBottom="4dp"
+ android:paddingTop="4dp"
+ android:textColor="#fff" />
+ </android.support.v4.view.ViewPager>
+</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/MusicActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/MusicActivity.java
new file mode 100644
index 00000000..36d3f068
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/MusicActivity.java
@@ -0,0 +1,146 @@
+package github.daneren2005.dsub.activity;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.fragments.MainFragment;
+import github.daneren2005.dsub.fragments.SubsonicTabFragment;
+import github.daneren2005.dsub.service.DownloadServiceImpl;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.Util;
+
+public class MusicActivity extends SubsonicActivity {
+ private static final String TAG = MusicActivity.class.getSimpleName();
+ private static boolean infoDialogDisplayed;
+ private MainActivityPagerAdapter pagerAdapter;
+ private ViewPager viewPager;
+ private SubsonicTabFragment prevPageFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
+ exit();
+ }
+ setContentView(R.layout.music);
+
+ pagerAdapter = new MainActivityPagerAdapter(getSupportFragmentManager());
+ viewPager = (ViewPager) findViewById(R.id.pager);
+ viewPager.setAdapter(pagerAdapter);
+ viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ notifyFragmentOnPageSelected(position);
+ }
+ });
+
+ if (savedInstanceState == null) {
+ int position = Util.isOffline(this) ? 0 : 2;
+ if (position == viewPager.getCurrentItem()) {
+ notifyFragmentOnPageSelected(position);
+ } else {
+ viewPager.setCurrentItem(position);
+ }
+ }
+
+ handleIntentAction(getIntent());
+ }
+
+ @Override
+ protected void onPostCreate(Bundle bundle) {
+ super.onPostCreate(bundle);
+
+ getSupportActionBar().setDisplayHomeAsUpEnabled(false);
+ getSupportActionBar().setHomeButtonEnabled(false);
+
+ showInfoDialog();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ handleIntentAction(intent);
+ // mPagerAdapter.notifyDataSetChanged();
+ }
+
+ private void handleIntentAction(Intent intent) {
+ if (intent.hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
+ exit();
+ }
+ }
+
+ private void exit() {
+ stopService(new Intent(this, DownloadServiceImpl.class));
+ finish();
+ }
+
+ private void showInfoDialog() {
+ if (!infoDialogDisplayed) {
+ infoDialogDisplayed = true;
+ if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) {
+ Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
+ }
+ }
+ }
+
+ private void notifyFragmentOnPageSelected(int position) {
+ /*if (prevPageFragment != null) {
+ prevPageFragment.onPageDeselected();
+ }
+ prevPageFragment = (SubsonicTabFragment) pagerAdapter.instantiateItem(viewPager, position);
+ prevPageFragment.onPageSelected();*/
+ }
+
+ public class MainActivityPagerAdapter extends FragmentPagerAdapter {
+
+ private final String [] titles = new String [] {
+ "Home",
+ "Library"
+ };
+
+ public MainActivityPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int i) {
+ Fragment fragment;
+ Bundle args = new Bundle();
+ switch(i) {
+ case 0:
+ fragment = new MainFragment();
+ break;
+
+ case 1:
+ fragment = new MainFragment();
+ break;
+ default:
+ fragment = null;
+ }
+
+ if (fragment != null) {
+ fragment.setArguments(args);
+ }
+
+ return fragment;
+ }
+
+ @Override
+ public int getCount() {
+ return 2;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return titles[position];
+ }
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java
new file mode 100644
index 00000000..55ac514f
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java
@@ -0,0 +1,194 @@
+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.util.Log;
+import android.view.KeyEvent;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.Window;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.service.DownloadService;
+import github.daneren2005.dsub.service.DownloadServiceImpl;
+import github.daneren2005.dsub.updates.Updater;
+import github.daneren2005.dsub.util.ImageLoader;
+import github.daneren2005.dsub.util.Util;
+import java.io.File;
+import java.io.PrintWriter;
+
+public class SubsonicActivity extends SherlockFragmentActivity {
+ private static final String TAG = SubsonicActivity.class.getSimpleName();
+ private static ImageLoader IMAGE_LOADER;
+ protected static String theme;
+ private boolean destroyed = false;
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ setUncaughtExceptionHandler();
+ applyTheme();
+ super.onCreate(bundle);
+ startService(new Intent(this, DownloadServiceImpl.class));
+ setVolumeControlStream(AudioManager.STREAM_MUSIC);
+ }
+
+ @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 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);
+ }
+
+ 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 ("light".equals(theme)) {
+ setTheme(R.style.Theme_DSub_Light);
+ } else if ("dark_fullscreen".equals(theme)) {
+ setTheme(R.style.Theme_DSub_Dark_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;
+ }
+
+ protected 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();
+ }
+
+ 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 void checkUpdates() {
+ try {
+ String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
+ int ver = Integer.parseInt(version.replace(".", ""));
+ Updater updater = new Updater(ver);
+ updater.checkUpdates(SubsonicActivity.this);
+ }
+ catch(Exception e) {
+
+ }
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
new file mode 100644
index 00000000..cdde2e77
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
@@ -0,0 +1,124 @@
+package github.daneren2005.dsub.fragments;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+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.util.Constants;
+import github.daneren2005.dsub.util.FileUtil;
+import github.daneren2005.dsub.util.MergeAdapter;
+import github.daneren2005.dsub.util.Util;
+import java.util.Arrays;
+
+public class MainFragment extends SubsonicTabFragment {
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ View view = inflater.inflate(R.layout.main, container, false);
+
+ loadSettings();
+
+ 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 dummyView = view.findViewById(R.id.main_dummy);
+
+ int instance = Util.getActiveServer(context);
+ String name = Util.getServerName(context, instance);
+ serverTextView.setText(name);
+
+ ListView list = (ListView) view.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, 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");
+ }
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ private void loadSettings() {
+ PreferenceManager.setDefaultValues(context, R.xml.settings, false);
+ SharedPreferences prefs = Util.getPreferences(context);
+ 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.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
+ editor.commit();
+ }
+ }
+
+ private void toggleOffline() {
+ Util.setOffline(this, !Util.isOffline(context));
+ restart();
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicTabFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicTabFragment.java
new file mode 100644
index 00000000..df98c710
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicTabFragment.java
@@ -0,0 +1,95 @@
+/*
+ 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.PackageInfo;
+import android.media.AudioManager;
+import android.media.MediaMetadataRetriever;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+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.SubsonicTabActivity;
+import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.domain.Playlist;
+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.updates.Updater;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.FileUtil;
+import github.daneren2005.dsub.util.ImageLoader;
+import github.daneren2005.dsub.util.LoadingTask;
+import github.daneren2005.dsub.util.ModalBackgroundTask;
+import github.daneren2005.dsub.util.SilentBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+public class SubsonicTabFragment extends SherlockFragment {
+ private static final String TAG = SubsonicTabActivity.class.getSimpleName();
+ private static ImageLoader IMAGE_LOADER;
+ protected Context context;
+
+ @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 = activity;
+ }
+
+ protected void restart() {
+
+ }
+}