Merge branch 'master' into dynamic_size_status_bars

This commit is contained in:
simonfi 2017-03-30 11:51:48 +13:00
commit a0c57357e3
32 changed files with 647 additions and 34 deletions

2
.gitignore vendored
View file

@ -40,5 +40,3 @@ captures/
# Mac
.DS_Store
/app/google-services.json

View file

@ -1,19 +1,27 @@
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
mavenCentral()
}
dependencies {
//noinspection GradleDynamicVersion
classpath 'io.fabric.tools:gradle:1.+'
classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'com.jakewharton.hugo'
apply plugin: 'com.google.gms.google-services'
repositories {
maven { url 'https://maven.fabric.io/public' }
maven { url "https://jitpack.io" }
maven {
name 'glide-snapshot'
url 'http://oss.sonatype.org/content/repositories/snapshots'
}
}
android {
@ -27,8 +35,8 @@ android {
vectorDrawables.useSupportLibrary = true
applicationId "com.kabouzeid.gramophone"
versionCode 128
versionName "0.14.0"
versionCode 130
versionName "0.15.0 BETA 1"
}
buildTypes {
release {
@ -39,6 +47,8 @@ android {
debug {
applicationIdSuffix '.debug'
versionNameSuffix ' DEBUG'
ext.enableCrashlytics = false // Disable fabric build ID generation for debug builds
}
}
packagingOptions {
@ -56,6 +66,10 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile('com.crashlytics.sdk.android:crashlytics:2.6.2@aar') {
transitive = true
}
compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.10.4@aar') {
transitive = true
}
@ -88,13 +102,13 @@ dependencies {
compile 'com.github.ksoichiro:android-observablescrollview:1.6.0'
compile 'com.github.kabouzeid:SeekArc:1.2-kmod'
compile 'com.github.kabouzeid:AndroidSlidingUpPanel:3.3.0-kmod3'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:retrofit:2.2.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
//noinspection GradleDynamicVersion
compile 'com.anjlab.android.iab.v3:library:1.0.+'
compile 'de.psdev.licensesdialog:licensesdialog:1.8.1'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
compile 'com.github.bumptech.glide:glide:3.8.0-SNAPSHOT'
compile 'com.github.bumptech.glide:okhttp3-integration:1.5.0-SNAPSHOT'
compile 'com.github.kabouzeid:RecyclerView-FastScroll:1.9-kmod'
compile 'com.heinrichreimersoftware:material-intro:1.6'
compile 'me.zhanghai.android.materialprogressbar:library:1.3.0'

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.kabouzeid.gramophone"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.kabouzeid.gramophone">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@ -173,6 +173,10 @@
<activity
android:name=".ui.activities.bugreport.BugReportActivity"
android:label="@string/report_an_issue" />
<activity
android:name=".appshortcuts.AppShortcutLauncherActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:launchMode="singleInstance"/>
</application>
</manifest>

View file

@ -25,6 +25,20 @@
<p>You can view the changelog dialog again at any time from the <i>about</i> section.</p>
<h3>Version 0.15.0 BETA 1</h3>
<ol>
<li><b>NEW:</b> App Shortcuts (Android Nougat only)</li>
</ol>
<h3>Version 0.14.1</h3>
<ol>
<li><b>FIX:</b> Notification won't disappear.</li>
<li><b>IMPROVEMENT:</b> Updated libraries.</li>
<li><b>IMPROVEMENT:</b> Synced translations.</li>
</ol>
<h3>Version 0.14.0</h3>
<ol>

View file

@ -1,10 +1,33 @@
package com.kabouzeid.gramophone;
import android.app.Application;
import android.os.Build;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.core.CrashlyticsCore;
import com.kabouzeid.gramophone.appshortcuts.DynamicShortcutManager;
import io.fabric.sdk.android.Fabric;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class App extends Application {
public static final String GOOGLE_PLAY_LICENSE_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjMeADN5Ffnt/ml5SYxNPCn8kGcOYGpHEfNSCts99vVxqmCn6C01E94c17j7rUK2aeHur5uxphZylzopPlQ8P8l1fqty0GPUNRSo18FCJzfGH8HZAwZYOcnRFPaXdaq3InyFJhBiODh2oeAcVK/idH6QraQ4r9HIlzigAg6lgwzxl2wJKDh7X/GMdDntCyzDh8xDQ0wIawFgvgojHwqh2Ci8Gnq6EYRwPA9yHiIIksT8Q30QyM5ewl5QcnWepsls7enNqeHarhpmSibRUDgCsxHoOpny7SyuvZvUI3wuLckDR0ds9hrt614scHHqDOBp/qWCZiAgOPVAEQcURbV09qQIDAQAB";
@Override
public void onCreate() {
super.onCreate();
// Set up Crashlytics, disabled for debug builds
Crashlytics crashlyticsKit = new Crashlytics.Builder()
.core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
.build();
Fabric.with(this, crashlyticsKit);
//Set up dynamic shortcuts
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
new DynamicShortcutManager(this).initDynamicShortcuts();
}
}
}

View file

@ -0,0 +1,71 @@
package com.kabouzeid.gramophone.appshortcuts;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.TypedValue;
import com.kabouzeid.appthemehelper.ThemeStore;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.kabouzeid.gramophone.util.Util;
/**
* @author Adrian Campos
*/
@RequiresApi(Build.VERSION_CODES.N_MR1)
public final class AppShortcutIconGenerator {
public static Icon generateThemedIcon(Context context, int iconId) {
if (PreferenceUtil.getInstance(context).coloredAppShortcuts()){
return generateUserThemedIcon(context, iconId);
} else {
return generateDefaultThemedIcon(context, iconId);
}
}
private static Icon generateDefaultThemedIcon(Context context, int iconId) {
//Return an Icon of iconId with default colors
return generateThemedIcon(context, iconId,
context.getColor(R.color.app_shortcut_default_foreground),
context.getColor(R.color.app_shortcut_default_background)
);
}
private static Icon generateUserThemedIcon(Context context, int iconId) {
//Get background color from context's theme
final TypedValue typedColorBackground = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.colorBackground, typedColorBackground, true);
//Return an Icon of iconId with those colors
return generateThemedIcon(context, iconId,
ThemeStore.primaryColor(context),
typedColorBackground.data
);
}
private static Icon generateThemedIcon(Context context, int iconId, int foregroundColor, int backgroundColor) {
//Get and tint foreground and background drawables
Drawable vectorDrawable = Util.getTintedVectorDrawable(context, iconId, foregroundColor);
Drawable backgroundDrawable = Util.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor);
//Squash the two drawables together
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{backgroundDrawable, vectorDrawable});
//Return as an Icon
return Icon.createWithBitmap(drawableToBitmap(layerDrawable));
}
private static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}

View file

@ -0,0 +1,85 @@
package com.kabouzeid.gramophone.appshortcuts;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.IntDef;
import com.kabouzeid.gramophone.appshortcuts.shortcuttype.LastAddedShortcutType;
import com.kabouzeid.gramophone.appshortcuts.shortcuttype.ShuffleAllShortcutType;
import com.kabouzeid.gramophone.appshortcuts.shortcuttype.TopTracksShortcutType;
import com.kabouzeid.gramophone.loader.LastAddedLoader;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.loader.TopAndRecentlyPlayedTracksLoader;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
* @author Adrian Campos
*/
public class AppShortcutLauncherActivity extends Activity {
public static final String KEY_SHORTCUT_TYPE = "com.kabouzeid.gramophone.appshortcuts.ShortcutType";
public static final int SHORTCUT_TYPE_SHUFFLE_ALL = 0;
public static final int SHORTCUT_TYPE_TOP_TRACKS = 1;
public static final int SHORTCUT_TYPE_LAST_ADDED = 2;
public static final int SHORTCUT_TYPE_NONE = 3;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ShortcutType
int shortcutType = SHORTCUT_TYPE_NONE;
//Set shortcutType from the intent extras
Bundle extras = getIntent().getExtras();
if (extras != null) {
//noinspection WrongConstant
shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE);
}
switch (shortcutType) {
case SHORTCUT_TYPE_SHUFFLE_ALL:
startServiceWithSongs(MusicService.SHUFFLE_MODE_SHUFFLE,
SongLoader.getAllSongs(getApplicationContext()));
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.getId());
break;
case SHORTCUT_TYPE_TOP_TRACKS:
startServiceWithSongs(MusicService.SHUFFLE_MODE_NONE,
TopAndRecentlyPlayedTracksLoader.getTopTracks(getApplicationContext()));
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.getId());
break;
case SHORTCUT_TYPE_LAST_ADDED:
startServiceWithSongs(MusicService.SHUFFLE_MODE_NONE,
LastAddedLoader.getLastAddedSongs(getApplicationContext()));
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.getId());
break;
}
finish();
}
private void startServiceWithSongs(int shuffleMode, ArrayList<Song> songs) {
Intent intent = new Intent(this, MusicService.class);
intent.setAction(MusicService.ACTION_PLAY);
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(MusicService.INTENT_EXTRA_SONGS, songs);
bundle.putInt(MusicService.INTENT_EXTRA_SHUFFLE_MODE, shuffleMode);
intent.putExtras(bundle);
startService(intent);
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({SHORTCUT_TYPE_SHUFFLE_ALL, SHORTCUT_TYPE_TOP_TRACKS, SHORTCUT_TYPE_LAST_ADDED, SHORTCUT_TYPE_NONE})
public @interface ShortcutType {
}
}

View file

@ -0,0 +1,63 @@
package com.kabouzeid.gramophone.appshortcuts;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.os.Build;
import com.kabouzeid.gramophone.appshortcuts.shortcuttype.LastAddedShortcutType;
import com.kabouzeid.gramophone.appshortcuts.shortcuttype.ShuffleAllShortcutType;
import com.kabouzeid.gramophone.appshortcuts.shortcuttype.TopTracksShortcutType;
import java.util.Arrays;
import java.util.List;
/**
* @author Adrian Campos
*/
@TargetApi(Build.VERSION_CODES.N_MR1)
public class DynamicShortcutManager {
private Context context;
private ShortcutManager shortcutManager;
public DynamicShortcutManager(Context context) {
this.context = context;
shortcutManager = this.context.getSystemService(ShortcutManager.class);
}
public static ShortcutInfo createShortcut(Context context, String id, String shortLabel, String longLabel, Icon icon, Intent intent) {
return new ShortcutInfo.Builder(context, id)
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIcon(icon)
.setIntent(intent)
.build();
}
public void initDynamicShortcuts() {
if (shortcutManager.getDynamicShortcuts().size() == 0) {
shortcutManager.setDynamicShortcuts(getDefaultShortcuts());
}
}
public void updateDynamicShortcuts() {
shortcutManager.updateShortcuts(getDefaultShortcuts());
}
public List<ShortcutInfo> getDefaultShortcuts() {
return (Arrays.asList(
new ShuffleAllShortcutType(context).getShortcutInfo(),
new TopTracksShortcutType(context).getShortcutInfo(),
new LastAddedShortcutType(context).getShortcutInfo()
));
}
public static void reportShortcutUsed(Context context, String shortcutId){
context.getSystemService(ShortcutManager.class).reportShortcutUsed(shortcutId);
}
}

View file

@ -0,0 +1,51 @@
package com.kabouzeid.gramophone.appshortcuts.shortcuttype;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public abstract class BaseShortcutType {
static final String ID_PREFIX = "com.kabouzeid.gramophone.appshortcuts.id.";
Context context;
public BaseShortcutType(Context context) {
this.context = context;
}
abstract ShortcutInfo getShortcutInfo();
static public String getId(){
return ID_PREFIX + "invalid";
}
/**
* Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode
*
* @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.)
* @return
*/
Intent getPlaySongsIntent(@AppShortcutLauncherActivity.ShortcutType int shortcutType) {
Intent intent = new Intent(context, AppShortcutLauncherActivity.class);
intent.setAction(Intent.ACTION_VIEW);
Bundle b = new Bundle();
b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType);
intent.putExtras(b);
return intent;
}
}

View file

@ -0,0 +1,33 @@
package com.kabouzeid.gramophone.appshortcuts.shortcuttype;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutIconGenerator;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public final class LastAddedShortcutType extends BaseShortcutType {
public LastAddedShortcutType(Context context) {
super(context);
}
public ShortcutInfo getShortcutInfo() {
return new ShortcutInfo.Builder(context, getId())
.setShortLabel(context.getString(R.string.app_shortcut_last_added_short))
.setLongLabel(context.getString(R.string.app_shortcut_last_added_long))
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_last_added))
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_LAST_ADDED))
.build();
}
public static String getId(){
return ID_PREFIX + "last_added";
}
}

View file

@ -0,0 +1,33 @@
package com.kabouzeid.gramophone.appshortcuts.shortcuttype;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutIconGenerator;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public final class ShuffleAllShortcutType extends BaseShortcutType {
public ShuffleAllShortcutType(Context context) {
super(context);
}
public ShortcutInfo getShortcutInfo() {
return new ShortcutInfo.Builder(context, getId())
.setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short))
.setLongLabel(context.getString(R.string.app_shortcut_shuffle_all_long))
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_shuffle_all))
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
.build();
}
public static String getId() {
return ID_PREFIX + "shuffle_all";
}
}

View file

@ -0,0 +1,33 @@
package com.kabouzeid.gramophone.appshortcuts.shortcuttype;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutIconGenerator;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public final class TopTracksShortcutType extends BaseShortcutType {
public TopTracksShortcutType(Context context) {
super(context);
}
public ShortcutInfo getShortcutInfo() {
return new ShortcutInfo.Builder(context, getId())
.setShortLabel(context.getString(R.string.app_shortcut_top_tracks_short))
.setLongLabel(context.getString(R.string.app_shortcut_top_tracks_long))
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_top_tracks))
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_TOP_TRACKS))
.build();
}
public static String getId() {
return ID_PREFIX + "top_tracks";
}
}

View file

@ -30,7 +30,6 @@ import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaButtonReceiver;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.widget.Toast;
@ -62,6 +61,7 @@ import com.kabouzeid.gramophone.util.Util;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author Karim Abou Zeid (kabouzeid), Andrew Neal
@ -79,6 +79,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
public static final String ACTION_SKIP = PHONOGRAPH_PACKAGE_NAME + ".skip";
public static final String ACTION_REWIND = PHONOGRAPH_PACKAGE_NAME + ".rewind";
public static final String ACTION_QUIT = PHONOGRAPH_PACKAGE_NAME + ".quitservice";
public static final String INTENT_EXTRA_SONGS = PHONOGRAPH_PACKAGE_NAME + ".intentextra.songs";
public static final String INTENT_EXTRA_SHUFFLE_MODE = PHONOGRAPH_PACKAGE_NAME + ".intentextra.shufflemode";
public static final String APP_WIDGET_UPDATE = PHONOGRAPH_PACKAGE_NAME + ".appwidgetupdate";
public static final String EXTRA_APP_WIDGET_NAME = PHONOGRAPH_PACKAGE_NAME + "app_widget_name";
@ -295,6 +297,20 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
pause();
break;
case ACTION_PLAY:
ArrayList<Song> songs = intent.getParcelableArrayListExtra(INTENT_EXTRA_SONGS);
if (songs != null) {
int shuffleMode = intent.getIntExtra(INTENT_EXTRA_SHUFFLE_MODE, getShuffleMode());
if (intent.hasExtra(INTENT_EXTRA_SHUFFLE_MODE) && intent.getIntExtra(INTENT_EXTRA_SHUFFLE_MODE, 0) == SHUFFLE_MODE_SHUFFLE) {
int startPosition = 0;
if (!songs.isEmpty()) {
startPosition = new Random().nextInt(songs.size());
}
openQueue(songs, startPosition, false);
setShuffleMode(shuffleMode);
} else {
openQueue(songs, 0, false);
}
}
play();
break;
case ACTION_REWIND:
@ -522,9 +538,29 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
return (getAudioManager().requestAudioFocus(audioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
}
private void updateMediaSession() {
private void updateNotification() {
if (getCurrentSong().id != -1) {
playingNotification.update();
}
}
private void updateMediaSessionPlaybackState() {
mediaSession.setPlaybackState(
new PlaybackStateCompat.Builder()
.setActions(MEDIA_SESSION_ACTIONS)
.setState(isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED,
getPosition(), 1)
.build());
}
private void updateMediaSessionMetaData() {
final Song song = getCurrentSong();
if (song.id == -1) {
mediaSession.setMetadata(null);
return;
}
final MediaMetadataCompat.Builder metaData = new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, song.artistName)
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, song.artistName)
@ -568,7 +604,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
} else {
mediaSession.setMetadata(metaData.build());
}
}
private static Bitmap copy(Bitmap bitmap) {
@ -985,22 +1020,17 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private void handleChangeInternal(@NonNull final String what) {
switch (what) {
case PLAY_STATE_CHANGED:
updateNotification();
updateMediaSessionPlaybackState();
final boolean isPlaying = isPlaying();
playingNotification.update();
mediaSession.setPlaybackState(
new PlaybackStateCompat.Builder()
.setActions(MEDIA_SESSION_ACTIONS)
.setState(isPlaying ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED,
getPosition(), 1)
.build());
if (!isPlaying && getSongProgressMillis() > 0) {
savePositionInTrack();
}
songPlayCountHelper.notifyPlayStateChanged(isPlaying);
break;
case META_CHANGED:
playingNotification.update();
updateMediaSession();
updateNotification();
updateMediaSessionMetaData();
savePosition();
savePositionInTrack();
final Song currentSong = getCurrentSong();
@ -1011,12 +1041,12 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
songPlayCountHelper.notifySongChanged(currentSong);
break;
case QUEUE_CHANGED:
updateMediaSession();
updateMediaSessionMetaData(); // because playing queue size might have changed
saveState();
if (playingQueue.size() > 0) {
prepareNext();
} else {
quit();
playingNotification.stop();
}
break;
}
@ -1052,10 +1082,10 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
break;
case PreferenceUtil.ALBUM_ART_ON_LOCKSCREEN:
case PreferenceUtil.BLURRED_ALBUM_ART:
updateMediaSession();
updateMediaSessionMetaData();
break;
case PreferenceUtil.COLORED_NOTIFICATION:
playingNotification.update();
updateNotification();
break;
}
}

View file

@ -7,6 +7,8 @@ import com.kabouzeid.gramophone.service.MusicService;
*/
public interface PlayingNotification {
int NOTIFICATION_ID = 1;
void init(MusicService service);
void update();

View file

@ -133,7 +133,7 @@ public class PlayingNotificationImpl implements PlayingNotification {
if (stopped)
return; // notification has been stopped before loading was finished
service.startForeground(1, notification);
service.startForeground(NOTIFICATION_ID, notification);
}
private void setBackgroundColor(int color) {

View file

@ -157,9 +157,9 @@ public class PlayingNotificationImpl24 implements PlayingNotification {
}
if (newNotifyMode == NOTIFY_MODE_FOREGROUND) {
service.startForeground(1, notification);
service.startForeground(NOTIFICATION_ID, notification);
} else if (newNotifyMode == NOTIFY_MODE_BACKGROUND) {
notificationManager.notify(1, notification);
notificationManager.notify(NOTIFICATION_ID, notification);
}
notifyMode = newNotifyMode;
@ -169,5 +169,6 @@ public class PlayingNotificationImpl24 implements PlayingNotification {
public synchronized void stop() {
stopped = true;
service.stopForeground(true);
notificationManager.cancel(NOTIFICATION_ID);
}
}

View file

@ -296,6 +296,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
} else {
MusicPlayerRemote.openQueue(songs, 0, true);
}
handled = true;
}
if (uri != null && uri.toString().length() > 0) {

View file

@ -25,6 +25,7 @@ import com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEColorPreference;
import com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appshortcuts.DynamicShortcutManager;
import com.kabouzeid.gramophone.preferences.NowPlayingScreenPreference;
import com.kabouzeid.gramophone.preferences.NowPlayingScreenPreferenceDialog;
import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity;
@ -82,6 +83,10 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
.commit();
break;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
new DynamicShortcutManager(this).updateDynamicShortcuts();
}
recreate();
}
@ -175,6 +180,13 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
ThemeStore.editTheme(getActivity())
.activityTheme(PreferenceUtil.getThemeResFromPrefValue((String) o))
.commit();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
//Set the new theme so that updateAppShortcuts can pull it
getActivity().setTheme(PreferenceUtil.getThemeResFromPrefValue((String) o));
new DynamicShortcutManager(getActivity()).updateDynamicShortcuts();
}
getActivity().recreate();
return true;
}
@ -240,6 +252,28 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
});
}
TwoStatePreference colorAppShortcuts = (TwoStatePreference) findPreference("should_color_app_shortcuts");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
colorAppShortcuts.setEnabled(false);
colorAppShortcuts.setSummary(R.string.pref_only_nougat_mr1);
} else {
colorAppShortcuts.setChecked(PreferenceUtil.getInstance(getActivity()).coloredAppShortcuts());
colorAppShortcuts.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//Save preference
PreferenceUtil.getInstance(getActivity()).setColoredAppShortcuts((Boolean)newValue);
//Update app shortcuts
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
new DynamicShortcutManager(getActivity()).updateDynamicShortcuts();
}
return true;
}
});
}
Preference equalizer = findPreference("equalizer");
if (!hasEqualizer()) {
equalizer.setEnabled(false);

View file

@ -319,7 +319,6 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
try {
return AudioFileIO.read(new File(song.data)).getTagOrCreateDefault().getFirst(FieldKey.LYRICS);
} catch (Exception e) {
e.printStackTrace();
cancel(false);
return null;
}

View file

@ -319,7 +319,6 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
try {
return AudioFileIO.read(new File(song.data)).getTagOrCreateDefault().getFirst(FieldKey.LYRICS);
} catch (Exception e) {
e.printStackTrace();
cancel(false);
return null;
}

View file

@ -44,6 +44,7 @@ public final class PreferenceUtil {
public static final String FORCE_SQUARE_ALBUM_COVER = "force_square_album_art";
public static final String COLORED_NOTIFICATION = "colored_notification";
public static final String COLORED_APP_SHORTCUTS = "colored_app_shortcuts";
public static final String AUDIO_DUCKING = "audio_ducking";
public static final String GAPLESS_PLAYBACK = "gapless_playback";
@ -148,6 +149,16 @@ public final class PreferenceUtil {
return mPreferences.getBoolean(COLORED_NOTIFICATION, true);
}
public void setColoredAppShortcuts(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(COLORED_APP_SHORTCUTS, value);
editor.apply();
}
public final boolean coloredAppShortcuts() {
return mPreferences.getBoolean(COLORED_APP_SHORTCUTS, true);
}
public final boolean gaplessPlayback() {
return mPreferences.getBoolean(GAPLESS_PLAYBACK, false);
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="176dp"
android:height="176dp"
android:viewportHeight="176"
android:viewportWidth="176">
<group
android:pivotX="88"
android:pivotY="88"
android:scaleX="0.916"
android:scaleY="0.916">
<path
android:name="ic_app_shortcut_background"
android:fillColor="#000"
android:pathData="M 88 0 C 136.601057985 0 176 39.3989420149 176 88 C 176 136.601057985 136.601057985 176 88 176 C 39.3989420149 176 0 136.601057985 0 88 C 0 39.3989420149 39.3989420149 0 88 0 Z" />
</group>
</vector>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="176dp"
android:height="176dp"
android:viewportHeight="176"
android:viewportWidth="176">
<group
android:pivotX="88"
android:pivotY="88"
android:scaleX="0.916"
android:scaleY="0.916"
android:translateX="-8"
android:translateY="-8">
<path
android:name="ic_app_shortcut_last_added_ic"
android:fillColor="#000"
android:pathData="M124.35,92h-16.2v16.2h-8.1V92H83.85v-8.1h16.2V67.65h8.1v16.2h16.2M128.4,55.5H79.8a8.1,8.1,0,0,0-8.1,8.1v48.6a8.1,8.1,0,0,0,8.1,8.1h48.6a8.1,8.1,0,0,0,8.1-8.1V63.6a8.1,8.1,0,0,0-8.1-8.1M63.6,71.7H55.5v56.7a8.1,8.1,0,0,0,8.1,8.1h56.7v-8.1H63.6Z" />
</group>
</vector>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="176dp"
android:height="176dp"
android:viewportHeight="176"
android:viewportWidth="176">
<group
android:pivotX="88"
android:pivotY="88"
android:scaleX="0.916"
android:scaleY="0.916"
android:translateX="-8"
android:translateY="-8">
<path
android:name="ic_app_shortcut_shuffle_ic"
android:fillColor="#000"
android:pathData="M110.15,103l-7,7,15.65,15.65L108.5,136H136V108.5l-10.2,10.2L110.15,103M108.5,56l10.2,10.2L56,128.95l7,7L125.8,73.3,136,83.5V56M89,81.85,63.05,56l-7,7L81.85,88.9Z" />
</group>
</vector>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="176dp"
android:height="176dp"
android:viewportHeight="176"
android:viewportWidth="176">
<group
android:pivotX="88"
android:pivotY="88"
android:scaleX="0.916"
android:scaleY="0.916"
android:translateX="-8"
android:translateY="-8">
<path
android:name="ic_app_shortcut_top_tracks_ic"
android:fillColor="#000"
android:pathData="M113.7,69.45l10.13,10.13-21.59,21.59-17.7-17.7L51.75,116.31,58,122.55,84.54,96l17.7,17.7,27.88-27.83L140.25,96V69.45Z" />
</group>
</vector>

View file

@ -20,6 +20,9 @@
<string name="action_search">搜索</string>
<string name="action_play_next">作为下一首播放</string>
<string name="action_play">播放</string>
<string name="action_play_pause">播放/暂停</string>
<string name="action_previous">上一首</string>
<string name="action_next">下一首</string>
<string name="action_add_to_playing_queue">加入播放队列</string>
<string name="action_remove_from_playing_queue">从播放队列中移除</string>
<string name="action_add_to_playlist">加入播放列表</string>
@ -45,6 +48,7 @@
<string name="year">年份</string>
<string name="track">音轨</string>
<string name="track_hint">"音轨(如用 2 表示第 2 首歌或用 3004 表示 CD3 里的第 4 首歌)"</string>
<string name="lyrics">歌词</string>
<string name="album_or_artist_empty">标题或艺术家名称为空</string>
<string name="saving_changes">正在保存更改…</string>
<string name="saving_to_file">保存至文件...</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="twenty_percent_black_overlay">#34000000</color>
<color name="app_shortcut_default_foreground">#607d8b</color>
<color name="app_shortcut_default_background">#f5f5f5</color>
</resources>

View file

@ -39,4 +39,6 @@
white-space: pre-wrap;
}
</string>
<string name="id_shortcuttype">com.kabouzeid.gramophone.appshortcuts.ShortcutType</string>
</resources>

View file

@ -119,6 +119,7 @@
<string name="pref_header_images">Images</string>
<string name="pref_header_lockscreen">Lockscreen</string>
<string name="pref_title_navigation_bar">Colored navigation bar</string>
<string name="pref_title_app_shortcuts">Colored app shortcuts</string>
<string name="pref_title_set_default_start_page">Start page</string>
<string name="pref_title_album_art_on_lockscreen">Show album cover</string>
<string name="pref_title_auto_download_artist_images">Auto download artist images</string>
@ -158,6 +159,7 @@
<string name="playlist_name_empty">Playlist name</string>
<string name="song">Song</string>
<string name="pref_only_lollipop">"Only available on Lollipop."</string>
<string name="pref_only_nougat_mr1">"Only available on Nougat 7.1."</string>
<string name="pref_summary_album_art_on_lockscreen">Uses the current songs album cover as lockscreen wallpaper.</string>
<string name="pref_summary_blurred_album_art">Blurs the album cover on the lockscreen. Can cause problems with third party apps and widgets.</string>
<string name="pref_summary_colored_notification">"Colors the notification in the album cover\u2019s vibrant color."</string>
@ -171,6 +173,7 @@
<string name="pref_summary_ignore_media_store_artwork">Can increase the album cover quality but causes slower image loading times. Only enable this if you have problems with low resolution artworks.</string>
<string name="pref_summary_colored_playback_controls_now_playing">Colors play/pause, shuffle and repeat as well as the progress slider in the album cover\u2019s vibrant color.</string>
<string name="pref_summary_colored_navigation_bar">Colors the navigation bar in the primary color.</string>
<string name="pref_summary_colored_app_shortcuts">Colors the app shortcuts in the primary color.</string>
<string name="pref_summary_audio_ducking">Notifications, navigation etc.</string>
<string name="could_not_download_album_cover">"Couldn\u2019t download a matching album cover."</string>
<string name="search_hint">Search your library…</string>
@ -275,4 +278,14 @@
<string name="copied_device_info_to_clipboard">Copied device info to clipboard.</string>
<string name="your_account_data_is_only_used_for_authentication">Your account data is only used for authentication.</string>
<string name="you_will_be_forwarded_to_the_issue_tracker_website">You will be forwarded to the issue tracker website.</string>
<!-- App Shortcuts -->
<string name="app_shortcut_shuffle_all_long">@string/action_shuffle_all</string>
<string name="app_shortcut_shuffle_all_short">Shuffle</string>
<string name="app_shortcut_top_tracks_long">@string/my_top_tracks</string>
<string name="app_shortcut_top_tracks_short">Top Tracks</string>
<string name="app_shortcut_last_added_long">@string/last_added</string>
<string name="app_shortcut_last_added_short">@string/last_added</string>
</resources>

View file

@ -48,4 +48,13 @@
<item name="android:transitionName" tools:ignore="NewApi">toolbar</item>
</style>
<style name="Theme.Transparent" parent="android:Theme">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
</resources>

View file

@ -27,6 +27,12 @@
android:summary="@string/pref_summary_colored_navigation_bar"
android:title="@string/pref_title_navigation_bar" />
<com.kabouzeid.appthemehelper.common.prefs.supportv7.ATESwitchPreference
android:defaultValue="true"
android:key="should_color_app_shortcuts"
android:summary="@string/pref_summary_colored_app_shortcuts"
android:title="@string/pref_title_app_shortcuts" />
</com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory>
</android.support.v7.preference.PreferenceScreen>

View file

@ -4,7 +4,6 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.google.gms:google-services:3.0.0'
}
}