/*
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.madmarty.madsonic.activity;
import java.io.File;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import android.annotation.SuppressLint;
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.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.Settings.Secure;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import github.madmarty.madsonic.R;
import github.madmarty.madsonic.domain.MusicDirectory;
import github.madmarty.madsonic.domain.Playlist;
import github.madmarty.madsonic.domain.Version;
import github.madmarty.madsonic.service.CachedMusicService;
import github.madmarty.madsonic.service.DownloadService;
import github.madmarty.madsonic.service.DownloadServiceImpl;
import github.madmarty.madsonic.service.MusicService;
import github.madmarty.madsonic.service.MusicServiceFactory;
import github.madmarty.madsonic.service.OfflineException;
import github.madmarty.madsonic.service.ServerTooOldException;
import github.madmarty.madsonic.util.Constants;
import github.madmarty.madsonic.util.ImageLoader;
import github.madmarty.madsonic.util.LoadingTask;
import github.madmarty.madsonic.util.ModalBackgroundTask;
import github.madmarty.madsonic.util.SilentBackgroundTask;
import github.madmarty.madsonic.util.Util;
import github.madmarty.madsonic.util.VideoPlayerType;
/**
* @author Sindre Mehus
*/
public class SubsonicTabActivity extends Activity {
private static final String TAG = SubsonicTabActivity.class.getSimpleName();
private static ImageLoader IMAGE_LOADER;
protected static String theme;
private boolean destroyed;
protected View mainBar;
protected static Version RESTVersion;
private View homeButton;
private View musicButton;
private View playlistButton;
private View playlistButtonSep;
private View chatButton;
private View chatButtonSep;
protected View searchButton;
private View searchButtonSep;
private View podcastButton;
private View podcastButtonSep;
private View nowPlayingButton;
protected Drawable largeUnknownImage;
protected CachedMusicService musicService;
private void exit() {
stopService(new Intent(this, DownloadServiceImpl.class));
Util.unregisterMediaButtonEventReceiver(this);
finish();
}
@Override
protected void onCreate(Bundle bundle) {
setUncaughtExceptionHandler();
Util.changeLanguage(getBaseContext());
applyTheme();
super.onCreate(bundle);
requestWindowFeature(Window.FEATURE_NO_TITLE);
startService(new Intent(this, DownloadServiceImpl.class));
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
@Override
protected void onPostCreate(Bundle bundle) {
super.onPostCreate(bundle);
homeButton = findViewById(R.id.button_bar_home);
homeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(SubsonicTabActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
}
});
musicButton = findViewById(R.id.button_bar_music);
musicButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(SubsonicTabActivity.this, SelectArtistActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
}
});
searchButton = findViewById(R.id.button_bar_search);
searchButtonSep = findViewById(R.id.search_separator);
searchButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startSearch(null, false, null, false);
}
});
podcastButton = findViewById(R.id.button_bar_podcast);
podcastButtonSep = findViewById(R.id.podcast_separator);
podcastButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(SubsonicTabActivity.this, SelectPodcastsActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_PODCAST, true);
Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
}
});
chatButton = findViewById(R.id.button_bar_chat);
chatButtonSep = findViewById(R.id.chat_separator);
chatButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Util.startActivityWithoutTransition(SubsonicTabActivity.this, ChatActivity.class);
}
});
playlistButton = findViewById(R.id.button_bar_playlists);
playlistButtonSep = findViewById(R.id.playlist_separator);
playlistButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(SubsonicTabActivity.this, SelectPlaylistActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
}
});
nowPlayingButton = findViewById(R.id.button_bar_now_playing);
nowPlayingButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
}
});
if (this instanceof MainActivity) {
homeButton.setEnabled(false);
} else if (this instanceof SelectAlbumActivity || this instanceof SelectArtistActivity) {
musicButton.setEnabled(false);
} else if (this instanceof SelectPodcastsActivity) {
podcastButton.setEnabled(false);
podcastButtonSep.setVisibility(View.GONE);
} else if (this instanceof SearchActivity) {
searchButton.setEnabled(false);
searchButtonSep.setVisibility(View.GONE);
} else if (this instanceof SelectPlaylistActivity) {
playlistButton.setEnabled(false);
playlistButtonSep.setVisibility(View.GONE);
} else if (this instanceof DownloadActivity || this instanceof LyricsActivity) {
nowPlayingButton.setEnabled(false);
}
updateButtonVisibility();
}
@Override
protected void onResume() {
super.onResume();
Util.registerMediaButtonEventReceiver(this);
if (theme != null && !theme.equals(Util.getTheme(this))) {
restart();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// if (android.os.Build.VERSION.SDK_INT < 11) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.common, menu);
// }
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_rescan:
try {
musicService.startRescan(SubsonicTabActivity.this, null);
} catch (Exception e) {
e.printStackTrace();
}
return true;
case R.id.menu_exit:
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
Util.startActivityWithoutTransition(this, intent);
return true;
case R.id.menu_settings:
startActivity(new Intent(this, SettingsActivity.class));
return true;
case R.id.menu_help:
startActivity(new Intent(this, HelpActivity.class));
return true;
}
return false;
}
@Override
protected void onDestroy() {
Util.unregisterMediaButtonEventReceiver(this);
super.onDestroy();
destroyed = true;
getImageLoader().clear();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN;
boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP;
boolean isVolumeAdjust = isVolumeDown || isVolumeUp;
boolean isJukebox = getDownloadService() != null && getDownloadService().isJukeboxEnabled();
if (isVolumeAdjust && isJukebox) {
getDownloadService().adjustJukeboxVolume(isVolumeUp);
return true;
}
return super.onKeyDown(keyCode, event);
}
private void restart() {
Intent intent = new Intent(this, this.getClass());
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtras(getIntent());
Util.startActivityWithoutTransition(this, intent);
}
public void finish() {
super.finish();
Util.disablePendingTransition(this);
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
// Set the font of title in the action bar.
TextView text = (TextView) findViewById(R.id.actionbar_title_text);
// Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Storopia.ttf");
// Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/NiseSonic.ttf");
// Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Trendy.ttf");
// Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf");
// text.setTypeface(typeface);
text.setText(title);
}
@Override
public void setTitle(int titleId) {
setTitle(getString(titleId));
}
private void applyTheme() {
theme = Util.getTheme(this);
if ("Madsonic Dark".equals(theme)) {
setTheme(R.style.Madsonic_Dark);
} else if ("Madsonic Light".equals(theme)) {
setTheme(R.style.Madsonic_Light);
} else if ("Madsonic Holo".equals(theme)) {
setTheme(R.style.Madsonic_Holo);
} else if ("Madsonic Red".equals(theme)) {
setTheme(R.style.Madsonic_Red);
} else if ("Madsonic Pink".equals(theme)) {
setTheme(R.style.Madsonic_Pink);
} else if ("Madsonic Flawless".equals(theme)) {
setTheme(R.style.Madsonic_Green);
} else if ("Madsonic Dark Fullscreen".equals(theme)) {
setTheme(R.style.Madsonic_Dark_Fullscreen);
} else if ("Madsonic Light Fullscreen".equals(theme)) {
setTheme(R.style.Madsonic_Light_Fullscreen);
} else if ("Madsonic Holo Fullscreen".equals(theme)) {
setTheme(R.style.Madsonic_Holo_Fullscreen);
} else if ("Madsonic Red Fullscreen".equals(theme)) {
setTheme(R.style.Madsonic_Red_Fullscreen);
} else if ("Madsonic Pink Fullscreen".equals(theme)) {
setTheme(R.style.Madsonic_Pink_Fullscreen);
} else if ("Madsonic Flawless Fullscreen".equals(theme)) {
setTheme(R.style.Madsonic_Green_Fullscreen);
}
}
@SuppressLint("Override") public boolean isDestroyed() {
return destroyed;
}
private void updateButtonVisibility() {
int visibility = Util.isOffline(this) ? View.GONE : View.VISIBLE;
SharedPreferences prefs = Util.getPreferences(this);
if(prefs.getBoolean(Constants.PREFERENCES_KEY_CHAT_ENABLED, true)) {
chatButton.setVisibility(visibility);
chatButtonSep.setVisibility(visibility);
} else {
chatButton.setVisibility(View.GONE);
chatButtonSep.setVisibility(View.GONE);
}
if(prefs.getBoolean(Constants.PREFERENCES_KEY_SEARCH_ENABLED, true)) {
searchButton.setVisibility(visibility);
searchButtonSep.setVisibility(visibility);
} else {
searchButton.setVisibility(View.GONE);
searchButtonSep.setVisibility(View.GONE);
}
if(prefs.getBoolean(Constants.PREFERENCES_KEY_PODCAST_ENABLED, true)) {
podcastButton.setVisibility(visibility);
podcastButtonSep.setVisibility(visibility);
} else {
podcastButton.setVisibility(View.GONE);
podcastButtonSep.setVisibility(View.GONE);
}
playlistButton.setVisibility(visibility);
playlistButtonSep.setVisibility(visibility);
}
public void toggleStarredInBackground(final MusicDirectory.Entry entry, final ImageButton button) {
final boolean starred = !entry.isStarred();
button.setImageResource(starred ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
entry.setStarred(starred);
// Util.toast(SubsonicTabActivity.this, getResources().getString(R.string.starring_content, entry.getTitle()));
new SilentBackgroundTask<Void>(this) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
musicService.setStarred(entry.getId(), starred, SubsonicTabActivity.this, null);
return null;
}
@Override
protected void done(Void result) {
// Util.toast(SubsonicTabActivity.this, getResources().getString(R.string.starring_content_done, entry.getTitle()));
}
@Override
protected void error(Throwable error) {
button.setImageResource(!starred ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
entry.setStarred(!starred);
String msg;
if (error instanceof OfflineException || error instanceof ServerTooOldException) {
msg = getErrorMessage(error);
} else {
msg = getResources().getString(R.string.starring_content_error, entry.getTitle()) + " " + getErrorMessage(error);
}
Util.toast(SubsonicTabActivity.this, msg, false);
}
}.execute();
}
public void setProgressVisible(boolean visible) {
View view = findViewById(R.id.tab_progress);
if (view != null) {
view.setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
public void updateProgress(String message) {
TextView view = (TextView) findViewById(R.id.tab_progress_message);
if (view != null) {
view.setText(message);
}
}
public DownloadService getDownloadService() {
// If service is not available, request it to start and wait for it.
for (int i = 0; i < 5; i++) {
DownloadService downloadService = DownloadServiceImpl.getInstance();
if (downloadService != null) {
return downloadService;
}
Log.w(TAG, "DownloadService not running. Attempting to start it.");
startService(new Intent(this, DownloadServiceImpl.class));
Util.sleepQuietly(50L);
}
return DownloadServiceImpl.getInstance();
}
protected void warnIfNetworkOrStorageUnavailable() {
if (!Util.isExternalStoragePresent()) {
Util.toast(this, R.string.select_album_no_sdcard);
} else if (!Util.isOffline(this) && !Util.isNetworkConnected(this)) {
Util.toast(this, R.string.select_album_no_network);
}
}
protected synchronized ImageLoader getImageLoader() {
if (IMAGE_LOADER == null) {
IMAGE_LOADER = new ImageLoader(this);
}
return IMAGE_LOADER;
}
public synchronized static ImageLoader getStaticImageLoader(Context context) {
if (IMAGE_LOADER == null) {
IMAGE_LOADER = new ImageLoader(context);
}
return IMAGE_LOADER;
}
protected void setBackAction(final Runnable runnable) {
View backLayout = findViewById(R.id.actionbar_back_layout);
backLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
runnable.run();
}
});
// backLayout.setBackgroundResource(R.drawable.actionbar_button);
findViewById(R.id.actionbar_back).setVisibility(View.VISIBLE);
}
protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle) {
ModalBackgroundTask<List<MusicDirectory.Entry>> task = new ModalBackgroundTask<List<MusicDirectory.Entry>>(this, false) {
private static final int MAX_SONGS = 500;
@Override
protected List<MusicDirectory.Entry> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
MusicDirectory root = musicService.getMusicDirectory(id, false, SubsonicTabActivity.this, this);
List<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
getSongsRecursively(root, songs);
return songs;
}
private void getSongsRecursively(MusicDirectory parent, List<MusicDirectory.Entry> songs) throws Exception {
if (songs.size() > MAX_SONGS) {
return;
}
for (MusicDirectory.Entry song : parent.getChildren(false, true)) {
if (!song.isVideo()) {
songs.add(song);
}
}
for (MusicDirectory.Entry dir : parent.getChildren(true, false)) {
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
getSongsRecursively(musicService.getMusicDirectory(dir.getId(), false, SubsonicTabActivity.this, this), songs);
}
}
@Override
protected void done(List<MusicDirectory.Entry> songs) {
DownloadService downloadService = getDownloadService();
if (!songs.isEmpty() && downloadService != null) {
if (!append) {
downloadService.clear();
}
warnIfNetworkOrStorageUnavailable();
downloadService.download(songs, save, autoplay, false, shuffle);
Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
}
}
};
task.execute();
}
protected void playVideo(MusicDirectory.Entry entry) {
if (!Util.isNetworkConnected(this)) {
Util.toast(this, R.string.select_album_no_network);
return;
}
VideoPlayerType player = Util.getVideoPlayerType(this);
try {
player.playVideo(this, entry);
} catch (Exception e) {
Util.toast(this, e.getMessage(), false);
}
}
protected void addToPlaylist(final List<MusicDirectory.Entry> songs) {
if(songs.isEmpty()) {
Util.toast(this, "No songs selected");
return;
}
new LoadingTask<List<Playlist>>(this, true) {
@Override
protected List<Playlist> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
return musicService.getPlaylists(false, SubsonicTabActivity.this, this);
}
@Override
protected void done(final List<Playlist> playlists) {
List<String> names = new ArrayList<String>();
names.add("Create New");
for(Playlist playlist: playlists) {
names.add(playlist.getName());
}
AlertDialog.Builder builder = new AlertDialog.Builder(SubsonicTabActivity.this);
builder.setTitle("Add to Playlist")
.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 = getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error);
}
Util.toast(SubsonicTabActivity.this, msg, false);
}
}.execute();
}
private void addToPlaylist(final Playlist playlist, final List<MusicDirectory.Entry> songs) {
new SilentBackgroundTask<Void>(this) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
musicService.addToPlaylist(playlist.getId(), songs, SubsonicTabActivity.this, null);
return null;
}
@Override
protected void done(Void result) {
Util.toast(SubsonicTabActivity.this, 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 = getResources().getString(R.string.updated_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
}
Util.toast(SubsonicTabActivity.this, msg, false);
}
}.execute();
}
protected void createNewPlaylist(final List<MusicDirectory.Entry> songs, boolean getSuggestion) {
View layout = this.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);
Version version = Util.getServerRestVersion(this);
Version updatePlaylistVersion = new Version("1.8.0");
try {
if(version.compareTo(updatePlaylistVersion) >= 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 {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
playlistNameView.setText(dateFormat.format(new Date()));
}
} else {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
playlistNameView.setText(dateFormat.format(new Date()));
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
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>(this) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
musicService.createPlaylist(null, name, songs, SubsonicTabActivity.this, null);
return null;
}
@Override
protected void done(Void result) {
Util.toast(SubsonicTabActivity.this, R.string.download_playlist_done);
}
@Override
protected void error(Throwable error) {
String msg = SubsonicTabActivity.this.getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error);
Util.toast(SubsonicTabActivity.this, msg);
}
}.execute();
}
private void overwritePlaylist(final List<MusicDirectory.Entry> songs, final String name, final String id) {
new SilentBackgroundTask<Void>(this) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
MusicDirectory playlist = musicService.getPlaylist(id, name, SubsonicTabActivity.this, null);
List<MusicDirectory.Entry> toDelete = playlist.getChildren();
musicService.overwritePlaylist(id, name, toDelete.size(), songs, SubsonicTabActivity.this, null);
return null;
}
@Override
protected void done(Void result) {
Util.toast(SubsonicTabActivity.this, 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 = SubsonicTabActivity.this.getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error);
}
Util.toast(SubsonicTabActivity.this, msg, false);
}
}.execute();
}
private void setUncaughtExceptionHandler() {
Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
if (!(handler instanceof SubsonicUncaughtExceptionHandler)) {
Thread.setDefaultUncaughtExceptionHandler(new SubsonicUncaughtExceptionHandler(this));
}
}
/**
* Logs the stack trace of uncaught exceptions to a file on the SD card.
*/
private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private final Thread.UncaughtExceptionHandler defaultHandler;
private final Context context;
private SubsonicUncaughtExceptionHandler(Context context) {
this.context = context;
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
File file = null;
PrintWriter printWriter = null;
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo("github.madmarty.madsonic", 0);
file = new File(Environment.getExternalStorageDirectory(), "madsonic-stacktrace.txt");
printWriter = new PrintWriter(file);
printWriter.println("Android API level: " + Build.VERSION.SDK);
printWriter.println("Madsonic version name: " + packageInfo.versionName);
printWriter.println("Madsonic 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);
}
}
}
}
}