mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-07 04:23:21 +01:00
Add setting to show lockscreen music controls, fix Jukebox menu item, show album art in Album Track view
This commit is contained in:
parent
c58d1acf93
commit
b747bb28f9
@ -217,6 +217,8 @@
|
||||
<string name="settings.network_timeout_120000">120 seconds</string>
|
||||
<string name="settings.show_notification">Show Notification</string>
|
||||
<string name="settings.show_notification_summary">Show now playing notification in the status bar</string>
|
||||
<string name="settings.show_lockscreen_controls">Show Lock Screen Controls</string>
|
||||
<string name="settings.show_lockscreen_controls_summary">Show playback controls on the lock screen</string>
|
||||
<string name="settings.max_albums">Max Albums</string>
|
||||
<string name="settings.max_albums_5">5</string>
|
||||
<string name="settings.max_albums_10">10</string>
|
||||
|
@ -261,6 +261,12 @@
|
||||
a:summary="@string/settings.show_notification_summary"
|
||||
a:key="showNotification"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.show_lockscreen_controls"
|
||||
a:summary="@string/settings.show_lockscreen_controls_summary"
|
||||
a:key="showLockScreen"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
@ -98,7 +98,6 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
private ImageButton repeatButton;
|
||||
private MenuItem equalizerMenuItem;
|
||||
private MenuItem visualizerMenuItem;
|
||||
private MenuItem jukeboxMenuItem;
|
||||
private View toggleListButton;
|
||||
private ScheduledExecutorService executorService;
|
||||
private DownloadFile currentPlaying;
|
||||
@ -276,6 +275,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
onProgressChanged();
|
||||
}
|
||||
});
|
||||
|
||||
playlistView.setOnTouchListener(gestureListener);
|
||||
|
||||
registerForContextMenu(playlistView);
|
||||
@ -439,7 +439,6 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
MenuItem screenOption = menu.findItem(R.id.menu_screen_on_off);
|
||||
equalizerMenuItem = menu.findItem(R.id.download_equalizer);
|
||||
visualizerMenuItem = menu.findItem(R.id.download_visualizer);
|
||||
jukeboxMenuItem = menu.findItem(R.id.download_jukebox);
|
||||
|
||||
equalizerMenuItem.setEnabled(equalizerAvailable);
|
||||
equalizerMenuItem.setVisible(equalizerAvailable);
|
||||
@ -536,13 +535,11 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
boolean active = !visualizerView.isActive();
|
||||
visualizerView.setActive(active);
|
||||
getDownloadService().setShowVisualization(visualizerView.isActive());
|
||||
//updateButtons();
|
||||
Util.toast(DownloadActivity.this, active ? R.string.download_visualizer_on : R.string.download_visualizer_off);
|
||||
return true;
|
||||
case R.id.download_jukebox:
|
||||
boolean jukeboxEnabled = !getDownloadService().isJukeboxEnabled();
|
||||
getDownloadService().setJukeboxEnabled(jukeboxEnabled);
|
||||
//updateButtons();
|
||||
Util.toast(DownloadActivity.this, jukeboxEnabled ? R.string.download_jukebox_on : R.string.download_jukebox_off, false);
|
||||
return true;
|
||||
default:
|
||||
@ -742,9 +739,6 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
startButton.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (jukeboxMenuItem != null)
|
||||
jukeboxMenuItem.setEnabled(getDownloadService().isJukeboxEnabled());
|
||||
}
|
||||
|
||||
private class SongListAdapter extends ArrayAdapter<DownloadFile> {
|
||||
|
@ -18,9 +18,11 @@
|
||||
*/
|
||||
package net.sourceforge.subsonic.androidapp.activity;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
@ -606,6 +608,12 @@ public class SelectAlbumActivity extends SubsonicTabActivity {
|
||||
}
|
||||
|
||||
if (songCount > 0) {
|
||||
ActionBar actionBar = getActionBar();
|
||||
|
||||
if (actionBar != null) {
|
||||
getImageLoader().setActionBarArtwork(selectButton, entries.get(0), actionBar);
|
||||
}
|
||||
|
||||
entryList.addFooterView(footer);
|
||||
selectButton.setVisibility(View.VISIBLE);
|
||||
playNowButton.setVisibility(View.VISIBLE);
|
||||
|
@ -741,7 +741,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
|
||||
}
|
||||
|
||||
private void setRemoteControl() {
|
||||
if (Util.getMediaButtonsPreference(this)) {
|
||||
if (Util.isLockScreenEnabled(this)) {
|
||||
AudioManager audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
|
||||
audioManager.requestAudioFocus(_afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
|
@ -38,12 +38,12 @@ public class MusicDirectoryEntryParser extends AbstractParser {
|
||||
entry.setDirectory(getBoolean("isDir"));
|
||||
entry.setCoverArt(get("coverArt"));
|
||||
entry.setArtist(get("artist"));
|
||||
entry.setYear(getInteger("year"));
|
||||
entry.setStarred(getValueExists("starred"));
|
||||
|
||||
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"));
|
||||
|
@ -78,6 +78,7 @@ public final class Constants {
|
||||
public static final String PREFERENCES_KEY_BUFFER_LENGTH = "bufferLength";
|
||||
public static final String PREFERENCES_KEY_NETWORK_TIMEOUT = "networkTimeout";
|
||||
public static final String PREFERENCES_KEY_SHOW_NOTIFICATION = "showNotification";
|
||||
public static final String PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS = "showLockScreen";
|
||||
public static final String PREFERENCES_KEY_MAX_ALBUMS = "maxAlbums";
|
||||
public static final String PREFERENCES_KEY_MAX_SONGS = "maxSongs";
|
||||
public static final String PREFERENCES_KEY_MAX_ARTISTS = "maxArtists";
|
||||
|
@ -1,71 +1,74 @@
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2010 (C) Sindre Mehus
|
||||
*/
|
||||
package net.sourceforge.subsonic.androidapp.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import net.sourceforge.subsonic.androidapp.activity.SubsonicTabActivity;
|
||||
import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
|
||||
|
||||
/**
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class EntryAdapter extends ArrayAdapter<MusicDirectory.Entry> {
|
||||
|
||||
private final SubsonicTabActivity activity;
|
||||
private final ImageLoader imageLoader;
|
||||
private final boolean checkable;
|
||||
|
||||
public EntryAdapter(SubsonicTabActivity activity, ImageLoader imageLoader, List<MusicDirectory.Entry> entries, boolean checkable) {
|
||||
super(activity, android.R.layout.simple_list_item_1, entries);
|
||||
this.activity = activity;
|
||||
this.imageLoader = imageLoader;
|
||||
this.checkable = checkable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
MusicDirectory.Entry entry = getItem(position);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
AlbumView view;
|
||||
// TODO: Reuse AlbumView objects once cover art loading is working.
|
||||
// if (convertView != null && convertView instanceof AlbumView) {
|
||||
// view = (AlbumView) convertView;
|
||||
// } else {
|
||||
view = new AlbumView(activity);
|
||||
// }
|
||||
view.setAlbum(entry, imageLoader);
|
||||
return view;
|
||||
|
||||
} else {
|
||||
SongView view;
|
||||
if (convertView != null && convertView instanceof SongView) {
|
||||
view = (SongView) convertView;
|
||||
} else {
|
||||
view = new SongView(activity);
|
||||
}
|
||||
view.setSong(entry, checkable);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2010 (C) Sindre Mehus
|
||||
*/
|
||||
package net.sourceforge.subsonic.androidapp.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import net.sourceforge.subsonic.androidapp.activity.SubsonicTabActivity;
|
||||
import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
|
||||
|
||||
/**
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class EntryAdapter extends ArrayAdapter<MusicDirectory.Entry> {
|
||||
|
||||
private final SubsonicTabActivity activity;
|
||||
private final ImageLoader imageLoader;
|
||||
private final boolean checkable;
|
||||
|
||||
public EntryAdapter(SubsonicTabActivity activity, ImageLoader imageLoader, List<MusicDirectory.Entry> entries, boolean checkable) {
|
||||
super(activity, android.R.layout.simple_list_item_1, entries);
|
||||
this.activity = activity;
|
||||
this.imageLoader = imageLoader;
|
||||
this.checkable = checkable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
MusicDirectory.Entry entry = getItem(position);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
AlbumView view;
|
||||
|
||||
if (convertView != null && convertView instanceof AlbumView) {
|
||||
view = (AlbumView) convertView;
|
||||
} else {
|
||||
view = new AlbumView(activity);
|
||||
}
|
||||
|
||||
view.setAlbum(entry, imageLoader);
|
||||
return view;
|
||||
|
||||
} else {
|
||||
SongView view;
|
||||
|
||||
if (convertView != null && convertView instanceof SongView) {
|
||||
view = (SongView) convertView;
|
||||
} else {
|
||||
view = new SongView(activity);
|
||||
}
|
||||
|
||||
view.setSong(entry, checkable);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package net.sourceforge.subsonic.androidapp.util;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
@ -29,6 +30,7 @@ import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.TransitionDrawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@ -60,6 +62,7 @@ public class ImageLoader implements Runnable {
|
||||
private final int imageSizeDefault;
|
||||
private final int imageSizeLarge;
|
||||
private Drawable largeUnknownImage;
|
||||
private Drawable drawable;
|
||||
|
||||
public ImageLoader(Context context) {
|
||||
queue = new LinkedBlockingQueue<Task>(500);
|
||||
@ -67,7 +70,6 @@ public class ImageLoader implements Runnable {
|
||||
// Determine the density-dependent image sizes.
|
||||
imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight();
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
//imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels) * 0.6);
|
||||
imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels));
|
||||
|
||||
for (int i = 0; i < CONCURRENCY; i++) {
|
||||
@ -102,7 +104,46 @@ public class ImageLoader implements Runnable {
|
||||
}
|
||||
queue.offer(new Task(view, entry, size, large, large, crossfade));
|
||||
}
|
||||
|
||||
public void setActionBarArtwork(final View view, final MusicDirectory.Entry entry, final ActionBar ab) {
|
||||
if (entry == null || entry.getCoverArt() == null) {
|
||||
ab.setLogo(largeUnknownImage);
|
||||
}
|
||||
|
||||
final int size = imageSizeLarge;
|
||||
drawable = cache.get(getKey(entry.getCoverArt(), size));
|
||||
|
||||
if (drawable != null) {
|
||||
ab.setLogo(drawable);
|
||||
}
|
||||
|
||||
final Handler handler = new Handler(){
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
drawable = (Drawable) msg.obj;
|
||||
ab.setLogo(drawable);
|
||||
}
|
||||
};
|
||||
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(view.getContext());
|
||||
|
||||
try
|
||||
{
|
||||
Bitmap bitmap = musicService.getCoverArt(view.getContext(), entry, size, true, null);
|
||||
drawable = Util.createDrawableFromBitmap(view.getContext(), bitmap);
|
||||
Message msg = Message.obtain();
|
||||
msg.obj = drawable;
|
||||
handler.sendMessage(msg);
|
||||
cache.put(getKey(entry.getCoverArt(), size), drawable);
|
||||
} catch (Throwable x) {
|
||||
Log.e(TAG, "Failed to download album art.", x);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private String getKey(String coverArtId, int size) {
|
||||
return coverArtId + size;
|
||||
}
|
||||
@ -161,54 +202,6 @@ public class ImageLoader implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap createReflection(Bitmap originalImage) {
|
||||
|
||||
int width = originalImage.getWidth();
|
||||
int height = originalImage.getHeight();
|
||||
|
||||
// The gap we want between the reflection and the original image
|
||||
final int reflectionGap = 4;
|
||||
|
||||
// This will not scale but will flip on the Y axis
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.preScale(1, -1);
|
||||
|
||||
// Create a Bitmap with the flip matix applied to it.
|
||||
// We only want the bottom half of the image
|
||||
Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height / 2, width, height / 2, matrix, false);
|
||||
|
||||
// Create a new bitmap with same width but taller to fit reflection
|
||||
Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height / 2), Bitmap.Config.ARGB_8888);
|
||||
|
||||
// Create a new Canvas with the bitmap that's big enough for
|
||||
// the image plus gap plus reflection
|
||||
Canvas canvas = new Canvas(bitmapWithReflection);
|
||||
|
||||
// Draw in the original image
|
||||
canvas.drawBitmap(originalImage, 0, 0, null);
|
||||
|
||||
// Draw in the gap
|
||||
Paint defaultPaint = new Paint();
|
||||
canvas.drawRect(0, height, width, height + reflectionGap, defaultPaint);
|
||||
|
||||
// Draw in the reflection
|
||||
canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
|
||||
|
||||
// Create a shader that is a linear gradient that covers the reflection
|
||||
Paint paint = new Paint();
|
||||
LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0,
|
||||
bitmapWithReflection.getHeight() + reflectionGap, 0x70000000, 0xff000000,
|
||||
Shader.TileMode.CLAMP);
|
||||
|
||||
// Set the paint to use this shader (linear gradient)
|
||||
paint.setShader(shader);
|
||||
|
||||
// Draw a rectangle using the paint with our linear gradient
|
||||
canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint);
|
||||
|
||||
return bitmapWithReflection;
|
||||
}
|
||||
|
||||
private class Task {
|
||||
private final View view;
|
||||
private final MusicDirectory.Entry entry;
|
||||
@ -227,7 +220,7 @@ public class ImageLoader implements Runnable {
|
||||
this.crossfade = crossfade;
|
||||
handler = new Handler();
|
||||
}
|
||||
|
||||
|
||||
public void execute() {
|
||||
try {
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(view.getContext());
|
||||
|
@ -139,6 +139,11 @@ public class Util extends DownloadActivity {
|
||||
SharedPreferences prefs = getPreferences(context);
|
||||
return prefs.getBoolean(Constants.PREFERENCES_KEY_SHOW_NOTIFICATION, false);
|
||||
}
|
||||
|
||||
public static boolean isLockScreenEnabled(Context context) {
|
||||
SharedPreferences prefs = getPreferences(context);
|
||||
return prefs.getBoolean(Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS, false);
|
||||
}
|
||||
|
||||
public static void setActiveServer(Context context, int instance) {
|
||||
SharedPreferences prefs = getPreferences(context);
|
||||
@ -701,7 +706,7 @@ public class Util extends DownloadActivity {
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void startForeground(Service service, int notificationId, Notification notification) {
|
||||
// Service.startForeground() was introduced in Android 2.0.
|
||||
// Use reflection to maintain compatibility with 1.5.
|
||||
|
Loading…
x
Reference in New Issue
Block a user