Compare commits

...

7 Commits

Author SHA1 Message Date
f43acdec83
Merge branch 'master' into rasp 2022-09-14 11:46:20 +03:00
f88713544c
resume playback on bluetooth headset connected (wo static broadcast rcv) 2022-09-14 11:45:30 +03:00
Adrian Ulrich
0925e04a5b drop some cruft 2022-09-05 21:34:12 +02:00
Adrian Ulrich
c3175f756d make SDK33 happy
We have to upgrade the minsdk level to android 8 - which was released in 2017; 5 years ago.
2022-09-05 21:18:24 +02:00
Adrian Ulrich
fcb0941e7b upgrade SDK level to 33 2022-09-05 20:31:08 +02:00
018d2ecf0c
Make m3u8 playlists syncable instead of m3u 2022-08-17 11:25:22 +03:00
d2d933ed8f
Make bypass .nomedia, bypass .nomedia under Android 11+ (android.permission.MANAGE_EXTERNAL_STORAGE) update gradle to some higher version 2022-08-17 00:38:20 +03:00
22 changed files with 158 additions and 297 deletions

View File

@ -1,12 +1,7 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
lintOptions { compileSdkVersion 32
disable 'MissingTranslation'
disable 'ExtraTranslation'
}
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig { defaultConfig {
applicationId "ch.blinkenlights.android.vanilla" applicationId "ch.blinkenlights.android.vanilla"
@ -21,16 +16,17 @@ android {
zipAlignEnabled true zipAlignEnabled true
} }
} }
lint {
abortOnError false
disable 'MissingTranslation', 'ExtraTranslation'
}
lintOptions {
abortOnError false
}
} }
dependencies { dependencies {
implementation 'androidx.legacy:legacy-support-core-ui:1.0.0' implementation 'androidx.legacy:legacy-support-core-ui:1.0.0'
implementation 'androidx.media:media:1.2.1' implementation 'androidx.media:media:1.6.0'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.6.1'
implementation 'junit:junit:4.12' implementation 'junit:junit:4.12'
compileOnly 'androidx.annotation:annotation:1.0.0' compileOnly 'androidx.annotation:annotation:1.0.0'
} }

View File

@ -31,10 +31,14 @@ THE SOFTWARE.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- This is needed for isWiredHeadsetOn() to work in some cases. (bug?) --> <!-- This is needed for isWiredHeadsetOn() to work in some cases. (bug?) -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- Playlist shortcuts --> <!-- Playlist shortcuts -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- Needed for resume playback on bluetooth headset connected feature -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- Allow us to query plugins --> <!-- Allow us to query plugins -->
<queries> <queries>
<intent> <intent>
@ -69,6 +73,7 @@ THE SOFTWARE.
<activity <activity
android:name="LibraryActivity" android:name="LibraryActivity"
android:theme="@style/Library" android:theme="@style/Library"
android:exported="true"
android:launchMode="singleTask"> android:launchMode="singleTask">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -93,7 +98,8 @@ THE SOFTWARE.
android:launchMode="singleInstance" /> android:launchMode="singleInstance" />
<receiver <receiver
android:name=".OneCellWidget" android:name=".OneCellWidget"
android:label="Vanilla Music 1x1"> android:label="Vanilla Music 1x1"
android:exported="false">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
@ -103,7 +109,8 @@ THE SOFTWARE.
</receiver> </receiver>
<receiver <receiver
android:name=".FourLongWidget" android:name=".FourLongWidget"
android:label="Vanilla Music 4x1 A"> android:label="Vanilla Music 4x1 A"
android:exported="false">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
@ -113,7 +120,8 @@ THE SOFTWARE.
</receiver> </receiver>
<receiver <receiver
android:name=".FourWhiteWidget" android:name=".FourWhiteWidget"
android:label="Vanilla Music 4x1 White"> android:label="Vanilla Music 4x1 White"
android:exported="false">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
@ -123,7 +131,8 @@ THE SOFTWARE.
</receiver> </receiver>
<receiver <receiver
android:name=".WidgetE" android:name=".WidgetE"
android:label="Vanilla Music 4x1 B"> android:label="Vanilla Music 4x1 B"
android:exported="false">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
@ -133,7 +142,8 @@ THE SOFTWARE.
</receiver> </receiver>
<receiver <receiver
android:name=".FourSquareWidget" android:name=".FourSquareWidget"
android:label="Vanilla Music 2x2 A"> android:label="Vanilla Music 2x2 A"
android:exported="false">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
@ -143,7 +153,8 @@ THE SOFTWARE.
</receiver> </receiver>
<receiver <receiver
android:name=".WidgetD" android:name=".WidgetD"
android:label="Vanilla Music 2x2 B"> android:label="Vanilla Music 2x2 B"
android:exported="false">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
@ -151,12 +162,14 @@ THE SOFTWARE.
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/widget_d" /> android:resource="@xml/widget_d" />
</receiver> </receiver>
<receiver android:name="MediaButtonReceiver" > <receiver android:name="MediaButtonReceiver"
android:exported="true">
<intent-filter android:priority="999"> <intent-filter android:priority="999">
<action android:name="android.intent.action.MEDIA_BUTTON" /> <action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<service android:name="PlaybackService"> <service android:name="PlaybackService"
android:exported="false">
<intent-filter> <intent-filter>
<action android:name="ch.blinkenlights.android.vanilla.action.PLAY" /> <action android:name="ch.blinkenlights.android.vanilla.action.PLAY" />
<action android:name="ch.blinkenlights.android.vanilla.action.PAUSE" /> <action android:name="ch.blinkenlights.android.vanilla.action.PAUSE" />
@ -169,7 +182,7 @@ THE SOFTWARE.
<service <service
android:name=".ScheduledLibraryUpdate" android:name=".ScheduledLibraryUpdate"
android:permission="android.permission.BIND_JOB_SERVICE" android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/> android:exported="true" />
<activity <activity
android:name="PreferencesActivity" /> android:name="PreferencesActivity" />
@ -187,14 +200,17 @@ THE SOFTWARE.
<activity <activity
android:name="ShortcutPseudoActivity" android:name="ShortcutPseudoActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"> android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="false">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="AudioPickerActivity" android:theme="@style/PopupDialog" <activity android:name="AudioPickerActivity"
android:excludeFromRecents="true" android:exported="true" > android:theme="@style/PopupDialog"
android:excludeFromRecents="true"
android:exported="true" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
@ -218,6 +234,7 @@ THE SOFTWARE.
</activity> </activity>
<activity android:name="AudioSearchActivity" android:theme="@style/PopupDialog" <activity android:name="AudioSearchActivity" android:theme="@style/PopupDialog"
android:exported="true"
android:excludeFromRecents="true"> android:excludeFromRecents="true">
<intent-filter> <intent-filter>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" /> <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />

View File

@ -29,6 +29,9 @@ function show(n) {
<b>Changelog</b> [<a href='javascript:show("changelog")'>show</a>] <b>Changelog</b> [<a href='javascript:show("changelog")'>show</a>]
<pre id='changelog'> <pre id='changelog'>
<b>NEXT</b>
- <b>NEW</b> Upgraded Android SDK level to 33
<b>1.1.0</b> <b>1.1.0</b>
- <b>FIX</b> Unbreak plugin integration - <b>FIX</b> Unbreak plugin integration
- <b>FIX</b> Always show cover art in notification - <b>FIX</b> Always show cover art in notification

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016 - 2017 Adrian Ulrich <adrian@blinkenlights.ch> * Copyright (C) 2016 - 2022 Adrian Ulrich <adrian@blinkenlights.ch>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -26,6 +26,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException;
import android.util.Log; import android.util.Log;
public class MediaMetadataExtractor extends HashMap<String, ArrayList<String>> { public class MediaMetadataExtractor extends HashMap<String, ArrayList<String>> {
@ -316,7 +317,12 @@ public class MediaMetadataExtractor extends HashMap<String, ArrayList<String>> {
mediaTags.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO) == null || mediaTags.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO) == null ||
mediaTags.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO) != null || mediaTags.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO) != null ||
mediaTags.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION) == null) { mediaTags.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION) == null) {
mediaTags.release(); try {
mediaTags.release();
} catch (IOException e) {
Log.v("VanillaMusic", "mediaTags.release() failed: " + e);
}
return; return;
} }
@ -361,7 +367,11 @@ public class MediaMetadataExtractor extends HashMap<String, ArrayList<String>> {
// if bastp was able to parse it (which is stricter than Android's own parser) // if bastp was able to parse it (which is stricter than Android's own parser)
mIsMediaFile = (containsKey(TITLE) || containsKey(ALBUM) || containsKey(ARTIST) || !bastpType.equals("")); mIsMediaFile = (containsKey(TITLE) || containsKey(ALBUM) || containsKey(ARTIST) || !bastpType.equals(""));
mediaTags.release(); try {
mediaTags.release();
} catch (IOException e) {
Log.v("VanillaMusic", "mediaTags.release() failed: " + e);
}
} }
/** /**

View File

@ -445,8 +445,8 @@ public class MediaScanner implements Handler.Callback {
if (!dir.isDirectory()) if (!dir.isDirectory())
return; return;
if (new File(dir, ".nomedia").exists()) // if (new File(dir, ".nomedia").exists())
return; // return;
if (isDotfile(dir)) if (isDotfile(dir))
return; return;

View File

@ -293,7 +293,8 @@ public class BottomBarControls extends LinearLayout
* Because ...reasons. * Because ...reasons.
*/ */
private boolean menuMargin() { private boolean menuMargin() {
return ThemeHelper.usesHoloTheme() == false; // Was false for holo, maybe will be true again in the future? ;-)
return true;
} }
/** /**

View File

@ -127,16 +127,16 @@ public class FourLongWidget extends AppWidgetProvider {
int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME; int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME;
intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN); intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.cover, pendingIntent); views.setOnClickPendingIntent(R.id.cover, pendingIntent);
views.setOnClickPendingIntent(R.id.text_layout, pendingIntent); views.setOnClickPendingIntent(R.id.text_layout, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.play_pause, pendingIntent); views.setOnClickPendingIntent(R.id.play_pause, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.next, pendingIntent); views.setOnClickPendingIntent(R.id.next, pendingIntent);
manager.updateAppWidget(new ComponentName(context, FourLongWidget.class), views); manager.updateAppWidget(new ComponentName(context, FourLongWidget.class), views);

View File

@ -129,16 +129,16 @@ public class FourSquareWidget extends AppWidgetProvider {
int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME; int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME;
intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN); intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.title, pendingIntent); views.setOnClickPendingIntent(R.id.title, pendingIntent);
views.setOnClickPendingIntent(R.id.artist, pendingIntent); views.setOnClickPendingIntent(R.id.artist, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.play_pause, pendingIntent); views.setOnClickPendingIntent(R.id.play_pause, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.next, pendingIntent); views.setOnClickPendingIntent(R.id.next, pendingIntent);
manager.updateAppWidget(new ComponentName(context, FourSquareWidget.class), views); manager.updateAppWidget(new ComponentName(context, FourSquareWidget.class), views);

View File

@ -131,20 +131,20 @@ public class FourWhiteWidget extends AppWidgetProvider {
int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME; int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME;
intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN); intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.cover, pendingIntent); views.setOnClickPendingIntent(R.id.cover, pendingIntent);
views.setOnClickPendingIntent(R.id.text_layout, pendingIntent); views.setOnClickPendingIntent(R.id.text_layout, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.play_pause, pendingIntent); views.setOnClickPendingIntent(R.id.play_pause, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.next, pendingIntent); views.setOnClickPendingIntent(R.id.next, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_PREVIOUS_SONG); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_PREVIOUS_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.previous, pendingIntent); views.setOnClickPendingIntent(R.id.previous, pendingIntent);
manager.updateAppWidget(new ComponentName(context, FourWhiteWidget.class), views); manager.updateAppWidget(new ComponentName(context, FourWhiteWidget.class), views);

View File

@ -36,9 +36,12 @@ import android.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Color; import android.graphics.Color;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.provider.Settings;
import android.support.iosched.tabs.VanillaTabLayout; import android.support.iosched.tabs.VanillaTabLayout;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -54,6 +57,7 @@ import android.widget.TextView;
import android.widget.SearchView; import android.widget.SearchView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import java.io.File; import java.io.File;
@ -155,6 +159,7 @@ public class LibraryActivity
private LibraryAdapter mCurrentAdapter; private LibraryAdapter mCurrentAdapter;
@RequiresApi(api = Build.VERSION_CODES.R)
@Override @Override
public void onCreate(Bundle state) public void onCreate(Bundle state)
{ {
@ -188,6 +193,11 @@ public class LibraryActivity
PermissionRequestActivity.showWarning(this, getIntent()); PermissionRequestActivity.showWarning(this, getIntent());
} }
if (!Environment.isExternalStorageManager()) {
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivity(intent);
}
mVanillaTabLayout = (VanillaTabLayout)findViewById(R.id.sliding_tabs); mVanillaTabLayout = (VanillaTabLayout)findViewById(R.id.sliding_tabs);
mVanillaTabLayout.setOnPageChangeListener(pagerAdapter); mVanillaTabLayout.setOnPageChangeListener(pagerAdapter);

View File

@ -103,11 +103,11 @@ public class OneCellWidget extends AppWidgetProvider {
int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME; int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME;
intent = ShortcutPseudoActivity.getIntent(context, doubleTap ? PlaybackService.ACTION_TOGGLE_PLAYBACK_DELAYED : PlaybackService.ACTION_TOGGLE_PLAYBACK); intent = ShortcutPseudoActivity.getIntent(context, doubleTap ? PlaybackService.ACTION_TOGGLE_PLAYBACK_DELAYED : PlaybackService.ACTION_TOGGLE_PLAYBACK);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.play_pause, pendingIntent); views.setOnClickPendingIntent(R.id.play_pause, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, doubleTap ? PlaybackService.ACTION_NEXT_SONG_DELAYED : PlaybackService.ACTION_NEXT_SONG); intent = ShortcutPseudoActivity.getIntent(context, doubleTap ? PlaybackService.ACTION_NEXT_SONG_DELAYED : PlaybackService.ACTION_NEXT_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.next, pendingIntent); views.setOnClickPendingIntent(R.id.next, pendingIntent);

View File

@ -26,11 +26,15 @@ package ch.blinkenlights.android.vanilla;
import ch.blinkenlights.android.medialibrary.MediaLibrary; import ch.blinkenlights.android.medialibrary.MediaLibrary;
import ch.blinkenlights.android.medialibrary.LibraryObserver; import ch.blinkenlights.android.medialibrary.LibraryObserver;
import android.annotation.SuppressLint;
import android.app.Notification; import android.app.Notification;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.app.backup.BackupManager; import android.app.backup.BackupManager;
import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@ -437,6 +441,7 @@ public final class PlaybackService extends Service
*/ */
private BastpUtil mBastpUtil; private BastpUtil mBastpUtil;
@SuppressLint("InvalidWakeLockTag")
@Override @Override
public void onCreate() public void onCreate()
{ {
@ -496,6 +501,7 @@ public final class PlaybackService extends Service
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY); filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
registerReceiver(mReceiver, filter); registerReceiver(mReceiver, filter);
MediaLibrary.registerLibraryObserver(mObserver); MediaLibrary.registerLibraryObserver(mObserver);
@ -527,9 +533,7 @@ public final class PlaybackService extends Service
mAccelLast = SensorManager.GRAVITY_EARTH; mAccelLast = SensorManager.GRAVITY_EARTH;
setupSensor(); setupSensor();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ScheduledLibraryUpdate.scheduleUpdate(this);
ScheduledLibraryUpdate.scheduleUpdate(this);
}
} }
@Override @Override
@ -800,9 +804,6 @@ public final class PlaybackService extends Service
if(mMediaPlayerInitialized != true) if(mMediaPlayerInitialized != true)
return; return;
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
return; /* setNextMediaPlayer is supported since JB */
boolean doGapless = false; boolean doGapless = false;
int fa = finishAction(mState); int fa = finishAction(mState);
Song nextSong = getSong(1); Song nextSong = getSong(1);
@ -1162,7 +1163,7 @@ public final class PlaybackService extends Service
long[] androidIds = MediaUtils.getAndroidMediaIds(getApplicationContext(), song); long[] androidIds = MediaUtils.getAndroidMediaIds(getApplicationContext(), song);
if (mStockBroadcast) { if (mStockBroadcast) {
Intent intent = new Intent("com.android.music.playstatechanged"); Intent intent = new Intent("com.android.music.playstatechanged"); // TODO: Scrobbler interface
intent.putExtra("playing", (mState & FLAG_PLAYING) != 0); intent.putExtra("playing", (mState & FLAG_PLAYING) != 0);
intent.putExtra("track", song.title); intent.putExtra("track", song.title);
intent.putExtra("album", song.album); intent.putExtra("album", song.album);
@ -1479,6 +1480,22 @@ public final class PlaybackService extends Service
} }
} else if (Intent.ACTION_SCREEN_ON.equals(action)) { } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
userActionTriggered(); userActionTriggered();
} else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
// Resume playback on bluetooth headset connected
// TODO: Resume playback only if playback was paused by BECOMING NOISY
int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (state == BluetoothProfile.STATE_CONNECTED) {
// Move to -2.8 secs on resume
int deltedPosition = getPosition() - 2800;
if (deltedPosition > 0) {
seekToPosition(deltedPosition);
}
play();
}
} }
} }
} }
@ -2088,11 +2105,11 @@ public final class PlaybackService extends Service
case NOT_ACTION_NEXT_SONG: { case NOT_ACTION_NEXT_SONG: {
Intent intent = new Intent(this, PlaybackService.class); Intent intent = new Intent(this, PlaybackService.class);
intent.setAction(PlaybackService.ACTION_NEXT_SONG_AUTOPLAY); intent.setAction(PlaybackService.ACTION_NEXT_SONG_AUTOPLAY);
return PendingIntent.getService(this, 0, intent, 0); return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
} }
case NOT_ACTION_MINI_ACTIVITY: { case NOT_ACTION_MINI_ACTIVITY: {
Intent intent = new Intent(this, MiniPlaybackActivity.class); Intent intent = new Intent(this, MiniPlaybackActivity.class);
return PendingIntent.getActivity(this, 0, intent, 0); return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
} }
default: default:
Log.w("VanillaMusic", "Unknown value for notification_action. Defaulting to 0."); Log.w("VanillaMusic", "Unknown value for notification_action. Defaulting to 0.");
@ -2100,12 +2117,12 @@ public final class PlaybackService extends Service
case NOT_ACTION_MAIN_ACTIVITY: { case NOT_ACTION_MAIN_ACTIVITY: {
Intent intent = new Intent(this, LibraryActivity.class); Intent intent = new Intent(this, LibraryActivity.class);
intent.setAction(Intent.ACTION_MAIN); intent.setAction(Intent.ACTION_MAIN);
return PendingIntent.getActivity(this, 0, intent, 0); return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
} }
case NOT_ACTION_FULL_ACTIVITY: { case NOT_ACTION_FULL_ACTIVITY: {
Intent intent = new Intent(this, FullPlaybackActivity.class); Intent intent = new Intent(this, FullPlaybackActivity.class);
intent.setAction(Intent.ACTION_MAIN); intent.setAction(Intent.ACTION_MAIN);
return PendingIntent.getActivity(this, 0, intent, 0); return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
} }
} }
} }
@ -2146,11 +2163,11 @@ public final class PlaybackService extends Service
.setSubText(song.artist) .setSubText(song.artist)
.setContentIntent(mNotificationAction) .setContentIntent(mNotificationAction)
.addAction(new NotificationCompat.Action(R.drawable.previous, .addAction(new NotificationCompat.Action(R.drawable.previous,
getString(R.string.previous_song), PendingIntent.getService(this, 0, previous, 0))) getString(R.string.previous_song), PendingIntent.getService(this, 0, previous, PendingIntent.FLAG_IMMUTABLE)))
.addAction(new NotificationCompat.Action(playButton, .addAction(new NotificationCompat.Action(playButton,
getString(R.string.play_pause), PendingIntent.getService(this, 0, playPause, 0))) getString(R.string.play_pause), PendingIntent.getService(this, 0, playPause, PendingIntent.FLAG_IMMUTABLE)))
.addAction(new NotificationCompat.Action(R.drawable.next, .addAction(new NotificationCompat.Action(R.drawable.next,
getString(R.string.next_song), PendingIntent.getService(this, 0, next, 0))) getString(R.string.next_song), PendingIntent.getService(this, 0, next, PendingIntent.FLAG_IMMUTABLE)))
.setStyle(new androidx.media.app.NotificationCompat.MediaStyle() .setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mMediaSessionTracker.getSessionToken()) .setMediaSession(mMediaSessionTracker.getSessionToken())
.setShowActionsInCompactView(0, 1, 2)) .setShowActionsInCompactView(0, 1, 2))

View File

@ -63,7 +63,7 @@ public class PlaylistObserver extends SQLiteOpenHelper implements Handler.Callba
/** /**
* Extension to use for M3U files * Extension to use for M3U files
*/ */
private static final String M3U_EXT = ".m3u"; private static final String M3U_EXT = ".m3u8";
/** /**
* Line comment prefix for M3U files * Line comment prefix for M3U files
*/ */
@ -152,11 +152,7 @@ public class PlaylistObserver extends SQLiteOpenHelper implements Handler.Callba
MediaLibrary.unregisterLibraryObserver(mLibraryObserver); MediaLibrary.unregisterLibraryObserver(mLibraryObserver);
mFileObserver.stopWatching(); mFileObserver.stopWatching();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { mHandlerThread.quitSafely();
mHandlerThread.quitSafely();
} else {
mHandlerThread.quit();
}
mHandlerThread = null; mHandlerThread = null;
mHandler = null; mHandler = null;
} }

View File

@ -86,9 +86,7 @@ public class PreferencesActivity extends PreferenceActivity
loadHeadersFromResource(R.xml.preference_headers, tmp); loadHeadersFromResource(R.xml.preference_headers, tmp);
for(Header obj : tmp) { for(Header obj : tmp) {
// Themes are 5.x only, so do not add PreferencesTheme on holo devices target.add(obj);
if (!ThemeHelper.usesHoloTheme() || !obj.fragment.equals(PreferencesTheme.class.getName()))
target.add(obj);
} }
} }

View File

@ -27,10 +27,7 @@ public class RemoteControl {
* Returns a RemoteControl.Client implementation * Returns a RemoteControl.Client implementation
*/ */
public RemoteControl.Client getClient(Context context) { public RemoteControl.Client getClient(Context context) {
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? return new RemoteControlImplLp(context);
new RemoteControlImplLp(context) :
new RemoteControlImplICS(context) // legacy implementation, kept until we drop 4.x support
);
} }
/** /**

View File

@ -1,156 +0,0 @@
/*
* Copyright (C) 2015 Adrian Ulrich <adrian@blinkenlights.ch>
* Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package ch.blinkenlights.android.vanilla;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaMetadataRetriever;
import android.media.RemoteControlClient;
public class RemoteControlImplICS implements RemoteControl.Client {
/**
* Context of this instance
*/
private final Context mContext;
/**
* Used with updateRemote method.
*/
private RemoteControlClient mRemote;
/**
* Whether the cover should be shown. 1 for yes, 0 for no, -1 for
* uninitialized.
*/
private int mShowCover = -1;
/**
* Creates a new instance
*
* @param context The context to use
*/
public RemoteControlImplICS(Context context) {
mContext = context;
}
/**
* Perform initialization required for RemoteControlClient.
*/
public void initializeRemote() {
// make sure there is only one registered remote
unregisterRemote();
// Receive 'background' play button events
AudioManager audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
ComponentName receiver = new ComponentName(mContext.getPackageName(), MediaButtonReceiver.class.getName());
audioManager.registerMediaButtonEventReceiver(receiver);
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(new ComponentName(mContext.getPackageName(), MediaButtonReceiver.class.getName()));
PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(mContext, 0, mediaButtonIntent, 0);
RemoteControlClient remote = new RemoteControlClient(mediaPendingIntent);
// Things we can do (eg: buttons to display on lock screen)
int flags = RemoteControlClient.FLAG_KEY_MEDIA_NEXT
| RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS
| RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
| RemoteControlClient.FLAG_KEY_MEDIA_PLAY
| RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
remote.setTransportControlFlags(flags);
audioManager.registerRemoteControlClient(remote);
mRemote = remote;
}
/**
* Unregisters a remote control client
*/
public void unregisterRemote() {
if (mRemote != null) {
AudioManager audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
ComponentName receiver = new ComponentName(mContext.getPackageName(), MediaButtonReceiver.class.getName());
audioManager.unregisterMediaButtonEventReceiver(receiver);
audioManager.unregisterRemoteControlClient(mRemote);
mRemote = null;
}
}
/**
* Uninitializes our cached preferences, forcing a reload
*/
public void reloadPreference()
{
mShowCover = -1;
}
/**
* Update the remote with new metadata.
* {@link #initializeRemote()} must have been called
* first.
*
* @param song The song containing the new metadata.
* @param state PlaybackService state, used to determine playback state.
* @param keepPaused whether or not to keep the remote updated in paused mode
*/
public void updateRemote(Song song, int state, boolean keepPaused)
{
RemoteControlClient remote = mRemote;
if (remote == null)
return;
boolean isPlaying = ((state & PlaybackService.FLAG_PLAYING) != 0);
if (mShowCover == -1) {
SharedPreferences settings = SharedPrefHelper.getSettings(mContext);
mShowCover = settings.getBoolean(PrefKeys.COVER_ON_LOCKSCREEN, PrefDefaults.COVER_ON_LOCKSCREEN) ? 1 : 0;
}
remote.setPlaybackState(isPlaying ? RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_PAUSED);
RemoteControlClient.MetadataEditor editor = remote.editMetadata(true);
if (song != null && song.artist != null && song.album != null) {
String artist_album = song.artist + " - " + song.album;
artist_album = (song.artist.length() == 0 ? song.album : artist_album); // no artist ? -> only display album
artist_album = (song.album.length() == 0 ? song.artist : artist_album); // no album ? -> only display artist
editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, artist_album);
editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, song.title);
Bitmap bitmap = song.getMediumCover(mContext);
if (bitmap != null && mShowCover == 1 && (isPlaying || keepPaused)) {
// Create a copy of the cover art, since RemoteControlClient likes
// to recycle what we give it.
bitmap = bitmap.copy(Bitmap.Config.RGB_565, false);
} else {
// Some lockscreen implementations fail to clear the cover artwork
// if we send a null bitmap. We are creating a 16x16 transparent
// bitmap to work around this limitation.
bitmap = Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888);
}
editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, bitmap);
}
editor.apply();
}
}

View File

@ -38,31 +38,28 @@ public class ThemeHelper {
* and platform API. * and platform API.
*/ */
final public static int getThemeResource(Context context, int theme) { final public static int getThemeResource(Context context, int theme) {
if(usesHoloTheme() == false) { TypedArray ar = null;
TypedArray ar = null; switch (theme) {
case R.style.Playback:
switch (theme) { ar = context.getResources().obtainTypedArray(R.array.theme_category_playback);
case R.style.Playback: break;
ar = context.getResources().obtainTypedArray(R.array.theme_category_playback); case R.style.Library:
break; ar = context.getResources().obtainTypedArray(R.array.theme_category_library);
case R.style.Library: break;
ar = context.getResources().obtainTypedArray(R.array.theme_category_library); case R.style.BackActionBar:
break; ar = context.getResources().obtainTypedArray(R.array.theme_category_backactionbar);
case R.style.BackActionBar: break;
ar = context.getResources().obtainTypedArray(R.array.theme_category_backactionbar); case R.style.PopupDialog:
break; ar = context.getResources().obtainTypedArray(R.array.theme_category_popupdialog);
case R.style.PopupDialog: break;
ar = context.getResources().obtainTypedArray(R.array.theme_category_popupdialog); case R.style.BottomSheetDialog:
break; ar = context.getResources().obtainTypedArray(R.array.theme_category_bottomsheetdialog);
case R.style.BottomSheetDialog: break;
ar = context.getResources().obtainTypedArray(R.array.theme_category_bottomsheetdialog); default:
break; throw new IllegalArgumentException("setTheme() called with unknown theme!");
default:
throw new IllegalArgumentException("setTheme() called with unknown theme!");
}
theme = ar.getResourceId(getSelectedThemeIndex(context), -1);
ar.recycle();
} }
theme = ar.getResourceId(getSelectedThemeIndex(context), -1);
ar.recycle();
return theme; return theme;
} }
@ -73,14 +70,7 @@ public class ThemeHelper {
*/ */
final public static int getPlayButtonResource(boolean playing) final public static int getPlayButtonResource(boolean playing)
{ {
int playButton = 0; return playing ? R.drawable.widget_pause : R.drawable.widget_play;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Android >= 5.0 uses the dark version of this drawable
playButton = playing ? R.drawable.widget_pause : R.drawable.widget_play;
} else {
playButton = playing ? R.drawable.pause : R.drawable.play;
}
return playButton;
} }
/** /**
@ -89,12 +79,9 @@ public class ThemeHelper {
*/ */
final private static boolean usesDarkTheme(Context context) final private static boolean usesDarkTheme(Context context)
{ {
boolean useDark = false; final int idx = getSelectedThemeIndex(context);
if(usesHoloTheme() == false) { final String[] variants = context.getResources().getStringArray(R.array.theme_variant);
final int idx = getSelectedThemeIndex(context); boolean useDark = variants[idx].equals("dark");
final String[] variants = context.getResources().getStringArray(R.array.theme_variant);
useDark = variants[idx].equals("dark");
}
return useDark; return useDark;
} }
@ -117,13 +104,6 @@ public class ThemeHelper {
return 0; return 0;
} }
/**
* Returns TRUE if this device uses the HOLO (android 4) theme
*/
final public static boolean usesHoloTheme() {
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP);
}
/** /**
* Fetches a color resource from the current theme * Fetches a color resource from the current theme
*/ */
@ -138,9 +118,6 @@ public class ThemeHelper {
* Returns the color to be used to draw the placeholder cover. * Returns the color to be used to draw the placeholder cover.
*/ */
final public static int[] getDefaultCoverColors(Context context) { final public static int[] getDefaultCoverColors(Context context) {
if (usesHoloTheme()) // pre material device
return new int[] { 0xff000000, 0xff404040 };
int bg = fetchThemeColor(context, android.R.attr.colorBackground); int bg = fetchThemeColor(context, android.R.attr.colorBackground);
int diff = 0x00171717 * (bg > 0xFF888888 ? -1 : 1); int diff = 0x00171717 * (bg > 0xFF888888 ? -1 : 1);
return new int[]{ bg, bg+diff }; return new int[]{ bg, bg+diff };

View File

@ -124,27 +124,27 @@ public class WidgetD extends AppWidgetProvider {
int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME; int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME;
intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN); intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.cover, pendingIntent); views.setOnClickPendingIntent(R.id.cover, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.play_pause, pendingIntent); views.setOnClickPendingIntent(R.id.play_pause, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.next, pendingIntent); views.setOnClickPendingIntent(R.id.next, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_PREVIOUS_SONG); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_PREVIOUS_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.previous, pendingIntent); views.setOnClickPendingIntent(R.id.previous, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_CYCLE_SHUFFLE); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_CYCLE_SHUFFLE);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.shuffle, pendingIntent); views.setOnClickPendingIntent(R.id.shuffle, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_CYCLE_REPEAT); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_CYCLE_REPEAT);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.end_action, pendingIntent); views.setOnClickPendingIntent(R.id.end_action, pendingIntent);
manager.updateAppWidget(new ComponentName(context, WidgetD.class), views); manager.updateAppWidget(new ComponentName(context, WidgetD.class), views);

View File

@ -114,28 +114,28 @@ public class WidgetE extends AppWidgetProvider {
int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME; int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME;
intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN); intent = new Intent(context, LibraryActivity.class).setAction(Intent.ACTION_MAIN);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.title, pendingIntent); views.setOnClickPendingIntent(R.id.title, pendingIntent);
views.setOnClickPendingIntent(R.id.artist, pendingIntent); views.setOnClickPendingIntent(R.id.artist, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_TOGGLE_PLAYBACK);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.play_pause, pendingIntent); views.setOnClickPendingIntent(R.id.play_pause, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_NEXT_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.next, pendingIntent); views.setOnClickPendingIntent(R.id.next, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_PREVIOUS_SONG); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_PREVIOUS_SONG);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.previous, pendingIntent); views.setOnClickPendingIntent(R.id.previous, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_CYCLE_SHUFFLE); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_CYCLE_SHUFFLE);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.shuffle, pendingIntent); views.setOnClickPendingIntent(R.id.shuffle, pendingIntent);
intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_CYCLE_REPEAT); intent = ShortcutPseudoActivity.getIntent(context, PlaybackService.ACTION_CYCLE_REPEAT);
pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.end_action, pendingIntent); views.setOnClickPendingIntent(R.id.end_action, pendingIntent);
manager.updateAppWidget(new ComponentName(context, WidgetE.class), views); manager.updateAppWidget(new ComponentName(context, WidgetE.class), views);

View File

@ -151,13 +151,9 @@ public class FancyMenu {
*/ */
private Adapter assembleAdapter(ArrayList<ArrayList<FancyMenuItem>> items) { private Adapter assembleAdapter(ArrayList<ArrayList<FancyMenuItem>> items) {
final Adapter adapter = new Adapter(mContext, 0); final Adapter adapter = new Adapter(mContext, 0);
// spacers look awful on holo themes
final boolean usesSpacers = !ThemeHelper.usesHoloTheme();
for (ArrayList<FancyMenuItem> sub : items) { for (ArrayList<FancyMenuItem> sub : items) {
for (FancyMenuItem item : sub ) { for (FancyMenuItem item : sub ) {
if (usesSpacers || !item.isSpacer()) { adapter.add(item);
adapter.add(item);
}
} }
} }
return adapter; return adapter;

View File

@ -4,7 +4,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.0.0' classpath 'com.android.tools.build:gradle:7.2.2'
} }
} }
allprojects { allprojects {
@ -14,7 +14,7 @@ allprojects {
} }
} }
ext { ext {
compileSdkVersion = 30 compileSdkVersion = 33
targetSdkVersion = 30 targetSdkVersion = 33
minSdkVersion = 15 minSdkVersion = 26
} }

View File

@ -1,7 +1,6 @@
#Wed Jun 27 14:32:00 EDT 2018 #Sun Aug 14 22:38:11 MSK 2022
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip zipStoreBase=GRADLE_USER_HOME
distributionSha256Sum=10065868c78f1207afb3a92176f99a37d753a513dff453abb6b5cceda4058cda