lots of code refactoring
This commit is contained in:
parent
ce2f3104ab
commit
2f8b82a44e
49 changed files with 89 additions and 819 deletions
|
|
@ -18,15 +18,9 @@ import org.jellyfin.apiclient.model.logging.ILogger;
|
|||
import org.jellyfin.apiclient.model.serialization.IJsonSerializer;
|
||||
import org.jellyfin.apiclient.model.session.ClientCapabilities;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class App extends Application {
|
||||
|
||||
public static final String GOOGLE_PLAY_LICENSE_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjMeADN5Ffnt/ml5SYxNPCn8kGcOYGpHEfNSCts99vVxqmCn6C01E94c17j7rUK2aeHur5uxphZylzopPlQ8P8l1fqty0GPUNRSo18FCJzfGH8HZAwZYOcnRFPaXdaq3InyFJhBiODh2oeAcVK/idH6QraQ4r9HIlzigAg6lgwzxl2wJKDh7X/GMdDntCyzDh8xDQ0wIawFgvgojHwqh2Ci8Gnq6EYRwPA9yHiIIksT8Q30QyM5ewl5QcnWepsls7enNqeHarhpmSibRUDgCsxHoOpny7SyuvZvUI3wuLckDR0ds9hrt614scHHqDOBp/qWCZiAgOPVAEQcURbV09qQIDAQAB";
|
||||
public static final String PRO_VERSION_PRODUCT_ID = "pro_version";
|
||||
|
||||
private static App app;
|
||||
|
||||
private static ApiClient apiClient;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -54,8 +54,6 @@ public class DonationsDialog extends DialogFragment implements BillingProcessor.
|
|||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
billingProcessor = new BillingProcessor(getContext(), App.GOOGLE_PLAY_LICENSE_KEY, this);
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
View customView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_donation, null);
|
||||
ProgressBar progressBar = customView.findViewById(R.id.progress);
|
||||
|
|
|
|||
|
|
@ -32,8 +32,10 @@ import butterknife.ButterKnife;
|
|||
public class SleepTimerDialog extends DialogFragment {
|
||||
@BindView(R.id.seek_arc)
|
||||
SeekArc seekArc;
|
||||
|
||||
@BindView(R.id.timer_display)
|
||||
TextView timerDisplay;
|
||||
|
||||
@BindView(R.id.should_finish_last_song)
|
||||
CheckBox shouldFinishLastSong;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ import com.kabouzeid.gramophone.model.Song;
|
|||
import com.kabouzeid.gramophone.util.MusicUtil;
|
||||
|
||||
public class SongDetailDialog extends DialogFragment {
|
||||
|
||||
public static final String TAG = SongDetailDialog.class.getSimpleName();
|
||||
|
||||
@NonNull
|
||||
public static SongDetailDialog create(Song song) {
|
||||
SongDetailDialog dialog = new SongDetailDialog();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.kabouzeid.gramophone.dialogs;
|
|||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
package com.kabouzeid.gramophone.glide.audiocover;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.jaudiotagger.audio.mp3.MP3File;
|
||||
import org.jaudiotagger.tag.images.Artwork;
|
||||
|
||||
public class AudioFileCoverUtils {
|
||||
public static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png"};
|
||||
|
||||
public static InputStream fallback(String path) throws FileNotFoundException {
|
||||
// use embedded high resolution album art
|
||||
try {
|
||||
MP3File mp3File = new MP3File(path);
|
||||
if (mp3File.hasID3v2Tag()) {
|
||||
Artwork art = mp3File.getTag().getFirstArtwork();
|
||||
if (art != null) {
|
||||
byte[] imageData = art.getBinaryData();
|
||||
return new ByteArrayInputStream(imageData);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// log exceptions and continue to the other fallback method
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// look for album art in external files
|
||||
final File parent = new File(path).getParentFile();
|
||||
for (String fallback : FALLBACKS) {
|
||||
File cover = new File(parent, fallback);
|
||||
if (cover.exists()) {
|
||||
return new FileInputStream(cover);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,10 +22,6 @@ import java.util.Random;
|
|||
import java.util.WeakHashMap;
|
||||
|
||||
public class MusicPlayerRemote {
|
||||
|
||||
public static final String TAG = MusicPlayerRemote.class.getSimpleName();
|
||||
|
||||
@Nullable
|
||||
public static MusicService musicService;
|
||||
|
||||
private static final WeakHashMap<Context, ServiceBinder> mConnectionMap = new WeakHashMap<>();
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
public class ShuffleHelper {
|
||||
|
||||
public static void makeShuffleList(@NonNull List<Song> listToShuffle, final int current) {
|
||||
if (listToShuffle.isEmpty()) return;
|
||||
|
||||
if (current >= 0) {
|
||||
Song song = listToShuffle.remove(current);
|
||||
Collections.shuffle(listToShuffle);
|
||||
|
|
|
|||
|
|
@ -302,7 +302,6 @@ public class StackBlur {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class BlurTask implements Callable<Void> {
|
||||
|
|
@ -329,6 +328,5 @@ public class StackBlur {
|
|||
blurIteration(_src, _w, _h, _radius, _totalCores, _coreIndex, _round);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,34 +2,11 @@ package com.kabouzeid.gramophone.helper;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Simple thread safe stop watch.
|
||||
*
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class StopWatch {
|
||||
|
||||
/**
|
||||
* The time the stop watch was last started.
|
||||
*/
|
||||
private long startTime;
|
||||
|
||||
/**
|
||||
* The time elapsed before the current {@link #startTime}.
|
||||
*/
|
||||
private long previousElapsedTime;
|
||||
|
||||
/**
|
||||
* Whether the stop watch is currently running or not.
|
||||
*/
|
||||
private boolean isRunning;
|
||||
|
||||
/**
|
||||
* Starts or continues the stop watch.
|
||||
*
|
||||
* @see #pause()
|
||||
* @see #reset()
|
||||
*/
|
||||
public void start() {
|
||||
synchronized (this) {
|
||||
startTime = System.currentTimeMillis();
|
||||
|
|
@ -37,12 +14,6 @@ public class StopWatch {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the stop watch. It can be continued later from {@link #start()}.
|
||||
*
|
||||
* @see #start()
|
||||
* @see #reset()
|
||||
*/
|
||||
public void pause() {
|
||||
synchronized (this) {
|
||||
previousElapsedTime += System.currentTimeMillis() - startTime;
|
||||
|
|
@ -50,12 +21,6 @@ public class StopWatch {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops and resets the stop watch to zero milliseconds.
|
||||
*
|
||||
* @see #start()
|
||||
* @see #pause()
|
||||
*/
|
||||
public void reset() {
|
||||
synchronized (this) {
|
||||
startTime = 0;
|
||||
|
|
@ -64,15 +29,13 @@ public class StopWatch {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the total elapsed time in milliseconds
|
||||
*/
|
||||
public final long getElapsedTime() {
|
||||
synchronized (this) {
|
||||
long currentElapsedTime = 0;
|
||||
if (isRunning) {
|
||||
currentElapsedTime = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
|
||||
return previousElapsedTime + currentElapsedTime;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
package com.kabouzeid.gramophone.interfaces;
|
||||
|
||||
public interface LoaderIds {
|
||||
int ALBUM_DETAIL_ACTIVITY = 1;
|
||||
int ARTIST_DETAIL_ACTIVITY = 2;
|
||||
int PLAYLIST_DETAIL_ACTIVITY = 3;
|
||||
int GENRE_DETAIL_ACTIVITY = 4;
|
||||
int SEARCH_ACTIVITY = 5;
|
||||
int FOLDERS_FRAGMENT = 6;
|
||||
int ALBUMS_FRAGMENT = 7;
|
||||
int ARTISTS_FRAGMENT = 8;
|
||||
int PLAYLISTS_FRAGMENT = 9;
|
||||
int GENRES_FRAGMENT = 10;
|
||||
int SONGS_FRAGMENT = 11;
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ import com.kabouzeid.gramophone.util.PreferenceUtil;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class LibraryPreferenceDialog extends DialogFragment {
|
||||
public static LibraryPreferenceDialog newInstance() {
|
||||
return new LibraryPreferenceDialog();
|
||||
|
|
|
|||
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.kabouzeid.gramophone.provider;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class HistoryStore extends SQLiteOpenHelper {
|
||||
private static final int MAX_ITEMS_IN_DB = 100;
|
||||
|
||||
public static final String DATABASE_NAME = "history.db";
|
||||
private static final int VERSION = 1;
|
||||
@Nullable
|
||||
private static HistoryStore sInstance = null;
|
||||
|
||||
public HistoryStore(final Context context) {
|
||||
super(context, DATABASE_NAME, null, VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NonNull final SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS " + RecentStoreColumns.NAME + " ("
|
||||
+ RecentStoreColumns.ID + " LONG NOT NULL," + RecentStoreColumns.TIME_PLAYED
|
||||
+ " LONG NOT NULL);");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + RecentStoreColumns.NAME);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + RecentStoreColumns.NAME);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static synchronized HistoryStore getInstance(@NonNull final Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new HistoryStore(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public void addSongId(final long songId) {
|
||||
if (songId == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
// remove previous entries
|
||||
removeSongId(songId);
|
||||
|
||||
// add the entry
|
||||
final ContentValues values = new ContentValues(2);
|
||||
values.put(RecentStoreColumns.ID, songId);
|
||||
values.put(RecentStoreColumns.TIME_PLAYED, System.currentTimeMillis());
|
||||
database.insert(RecentStoreColumns.NAME, null, values);
|
||||
|
||||
// if our db is too large, delete the extra items
|
||||
Cursor oldest = null;
|
||||
try {
|
||||
oldest = database.query(RecentStoreColumns.NAME,
|
||||
new String[]{RecentStoreColumns.TIME_PLAYED}, null, null, null, null,
|
||||
RecentStoreColumns.TIME_PLAYED + " ASC");
|
||||
|
||||
if (oldest != null && oldest.getCount() > MAX_ITEMS_IN_DB) {
|
||||
oldest.moveToPosition(oldest.getCount() - MAX_ITEMS_IN_DB);
|
||||
long timeOfRecordToKeep = oldest.getLong(0);
|
||||
|
||||
database.delete(RecentStoreColumns.NAME,
|
||||
RecentStoreColumns.TIME_PLAYED + " < ?",
|
||||
new String[]{String.valueOf(timeOfRecordToKeep)});
|
||||
|
||||
}
|
||||
} finally {
|
||||
if (oldest != null) {
|
||||
oldest.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSongId(final long songId) {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
database.delete(RecentStoreColumns.NAME, RecentStoreColumns.ID + " = ?", new String[]{
|
||||
String.valueOf(songId)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
database.delete(RecentStoreColumns.NAME, null, null);
|
||||
}
|
||||
|
||||
public boolean contains(long id) {
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
Cursor cursor = database.query(RecentStoreColumns.NAME,
|
||||
new String[]{RecentStoreColumns.ID},
|
||||
RecentStoreColumns.ID + "=?",
|
||||
new String[]{String.valueOf(id)},
|
||||
null, null, null, null);
|
||||
|
||||
boolean containsId = cursor != null && cursor.moveToFirst();
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
return containsId;
|
||||
}
|
||||
|
||||
public Cursor queryRecentIds() {
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
return database.query(RecentStoreColumns.NAME,
|
||||
new String[]{RecentStoreColumns.ID}, null, null, null, null,
|
||||
RecentStoreColumns.TIME_PLAYED + " DESC");
|
||||
}
|
||||
|
||||
public interface RecentStoreColumns {
|
||||
String NAME = "recent_history";
|
||||
|
||||
String ID = "song_id";
|
||||
|
||||
String TIME_PLAYED = "time_played";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,408 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.kabouzeid.gramophone.provider;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This database tracks the number of play counts for an individual song. This is used to drive
|
||||
* the top played tracks as well as the playlist images
|
||||
*/
|
||||
public class SongPlayCountStore extends SQLiteOpenHelper {
|
||||
@Nullable
|
||||
private static SongPlayCountStore sInstance = null;
|
||||
|
||||
public static final String DATABASE_NAME = "song_play_count.db";
|
||||
private static final int VERSION = 2;
|
||||
|
||||
// interpolator curve applied for measuring the curve
|
||||
@NonNull
|
||||
private static Interpolator sInterpolator = new AccelerateInterpolator(1.5f);
|
||||
|
||||
// how many weeks worth of playback to track
|
||||
private static final int NUM_WEEKS = 52;
|
||||
|
||||
// how high to multiply the interpolation curve
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static int INTERPOLATOR_HEIGHT = 50;
|
||||
|
||||
// how high the base value is. The ratio of the Height to Base is what really matters
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static int INTERPOLATOR_BASE = 25;
|
||||
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static int ONE_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7;
|
||||
|
||||
@NonNull
|
||||
private static String WHERE_ID_EQUALS = SongPlayCountColumns.ID + "=?";
|
||||
|
||||
// number of weeks since epoch time
|
||||
private int mNumberOfWeeksSinceEpoch;
|
||||
|
||||
// used to track if we've walked through the db and updated all the rows
|
||||
private boolean mDatabaseUpdated;
|
||||
|
||||
public SongPlayCountStore(final Context context) {
|
||||
super(context, DATABASE_NAME, null, VERSION);
|
||||
|
||||
long msSinceEpoch = System.currentTimeMillis();
|
||||
mNumberOfWeeksSinceEpoch = (int) (msSinceEpoch / ONE_WEEK_IN_MS);
|
||||
|
||||
mDatabaseUpdated = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NonNull final SQLiteDatabase db) {
|
||||
// create the play count table
|
||||
// WARNING: If you change the order of these columns
|
||||
// please update getColumnIndexForWeek
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("CREATE TABLE IF NOT EXISTS ");
|
||||
builder.append(SongPlayCountColumns.NAME);
|
||||
builder.append("(");
|
||||
builder.append(SongPlayCountColumns.ID);
|
||||
builder.append(" INT UNIQUE,");
|
||||
|
||||
for (int i = 0; i < NUM_WEEKS; i++) {
|
||||
builder.append(getColumnNameForWeek(i));
|
||||
builder.append(" INT DEFAULT 0,");
|
||||
}
|
||||
|
||||
builder.append(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX);
|
||||
builder.append(" INT NOT NULL,");
|
||||
|
||||
builder.append(SongPlayCountColumns.PLAY_COUNT_SCORE);
|
||||
builder.append(" REAL DEFAULT 0);");
|
||||
|
||||
db.execSQL(builder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + SongPlayCountColumns.NAME);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// If we ever have downgrade, drop the table to be safe
|
||||
db.execSQL("DROP TABLE IF EXISTS " + SongPlayCountColumns.NAME);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context The {@link Context} to use
|
||||
* @return A new instance of this class.
|
||||
*/
|
||||
@NonNull
|
||||
public static synchronized SongPlayCountStore getInstance(@NonNull final Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new SongPlayCountStore(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the play count of a song by 1
|
||||
*
|
||||
* @param songId The song id to increase the play count
|
||||
*/
|
||||
public void bumpPlayCount(final long songId) {
|
||||
if (songId == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
updateExistingRow(database, songId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a new entry that indicates a song has been played once as well as its score
|
||||
*
|
||||
* @param database a write able database
|
||||
* @param songId the id of the track
|
||||
*/
|
||||
private void createNewPlayedEntry(@NonNull final SQLiteDatabase database, final long songId) {
|
||||
// no row exists, create a new one
|
||||
float newScore = getScoreMultiplierForWeek(0);
|
||||
int newPlayCount = 1;
|
||||
|
||||
final ContentValues values = new ContentValues(3);
|
||||
values.put(SongPlayCountColumns.ID, songId);
|
||||
values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, newScore);
|
||||
values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, mNumberOfWeeksSinceEpoch);
|
||||
values.put(getColumnNameForWeek(0), newPlayCount);
|
||||
|
||||
database.insert(SongPlayCountColumns.NAME, null, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will take a song entry and update it to the latest week and increase the count
|
||||
* for the current week by 1 if necessary
|
||||
*
|
||||
* @param database a writeable database
|
||||
* @param id the id of the track to bump
|
||||
* @param bumpCount whether to bump the current's week play count by 1 and adjust the score
|
||||
*/
|
||||
private void updateExistingRow(@NonNull final SQLiteDatabase database, final long id, boolean bumpCount) {
|
||||
String stringId = String.valueOf(id);
|
||||
|
||||
// begin the transaction
|
||||
database.beginTransaction();
|
||||
|
||||
// get the cursor of this content inside the transaction
|
||||
final Cursor cursor = database.query(SongPlayCountColumns.NAME, null, WHERE_ID_EQUALS,
|
||||
new String[]{stringId}, null, null, null);
|
||||
|
||||
// if we have a result
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
// figure how many weeks since we last updated
|
||||
int lastUpdatedIndex = cursor.getColumnIndex(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX);
|
||||
int lastUpdatedWeek = cursor.getInt(lastUpdatedIndex);
|
||||
int weekDiff = mNumberOfWeeksSinceEpoch - lastUpdatedWeek;
|
||||
|
||||
// if it's more than the number of weeks we track, delete it and create a new entry
|
||||
if (Math.abs(weekDiff) >= NUM_WEEKS) {
|
||||
// this entry needs to be dropped since it is too outdated
|
||||
deleteEntry(database, stringId);
|
||||
if (bumpCount) {
|
||||
createNewPlayedEntry(database, id);
|
||||
}
|
||||
} else if (weekDiff != 0) {
|
||||
// else, shift the weeks
|
||||
int[] playCounts = new int[NUM_WEEKS];
|
||||
|
||||
if (weekDiff > 0) {
|
||||
// time is shifted forwards
|
||||
for (int i = 0; i < NUM_WEEKS - weekDiff; i++) {
|
||||
playCounts[i + weekDiff] = cursor.getInt(getColumnIndexForWeek(i));
|
||||
}
|
||||
} else if (weekDiff < 0) {
|
||||
// time is shifted backwards (by user) - nor typical behavior but we
|
||||
// will still handle it
|
||||
|
||||
// since weekDiff is -ve, NUM_WEEKS + weekDiff is the real # of weeks we have to
|
||||
// transfer. Then we transfer the old week i - weekDiff to week i
|
||||
// for example if the user shifted back 2 weeks, ie -2, then for 0 to
|
||||
// NUM_WEEKS + (-2) we set the new week i = old week i - (-2) or i+2
|
||||
for (int i = 0; i < NUM_WEEKS + weekDiff; i++) {
|
||||
playCounts[i] = cursor.getInt(getColumnIndexForWeek(i - weekDiff));
|
||||
}
|
||||
}
|
||||
|
||||
// bump the count
|
||||
if (bumpCount) {
|
||||
playCounts[0]++;
|
||||
}
|
||||
|
||||
float score = calculateScore(playCounts);
|
||||
|
||||
// if the score is non-existant, then delete it
|
||||
if (score < .01f) {
|
||||
deleteEntry(database, stringId);
|
||||
} else {
|
||||
// create the content values
|
||||
ContentValues values = new ContentValues(NUM_WEEKS + 2);
|
||||
values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, mNumberOfWeeksSinceEpoch);
|
||||
values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, score);
|
||||
|
||||
for (int i = 0; i < NUM_WEEKS; i++) {
|
||||
values.put(getColumnNameForWeek(i), playCounts[i]);
|
||||
}
|
||||
|
||||
// update the entry
|
||||
database.update(SongPlayCountColumns.NAME, values, WHERE_ID_EQUALS,
|
||||
new String[]{stringId});
|
||||
}
|
||||
} else if (bumpCount) {
|
||||
// else no shifting, just update the scores
|
||||
ContentValues values = new ContentValues(2);
|
||||
|
||||
// increase the score by a single score amount
|
||||
int scoreIndex = cursor.getColumnIndex(SongPlayCountColumns.PLAY_COUNT_SCORE);
|
||||
float score = cursor.getFloat(scoreIndex) + getScoreMultiplierForWeek(0);
|
||||
values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, score);
|
||||
|
||||
// increase the play count by 1
|
||||
values.put(getColumnNameForWeek(0), cursor.getInt(getColumnIndexForWeek(0)) + 1);
|
||||
|
||||
// update the entry
|
||||
database.update(SongPlayCountColumns.NAME, values, WHERE_ID_EQUALS,
|
||||
new String[]{stringId});
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
} else if (bumpCount) {
|
||||
// if we have no existing results, create a new one
|
||||
createNewPlayedEntry(database, id);
|
||||
}
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
database.delete(SongPlayCountColumns.NAME, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a cursor containing the top songs played. Note this only returns songs that have been
|
||||
* played at least once in the past NUM_WEEKS
|
||||
*
|
||||
* @param numResults number of results to limit by. If <= 0 it returns all results
|
||||
* @return the top tracks
|
||||
*/
|
||||
public Cursor getTopPlayedResults(int numResults) {
|
||||
updateResults();
|
||||
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
return database.query(SongPlayCountColumns.NAME, new String[]{SongPlayCountColumns.ID},
|
||||
null, null, null, null, SongPlayCountColumns.PLAY_COUNT_SCORE + " DESC",
|
||||
(numResults <= 0 ? null : String.valueOf(numResults)));
|
||||
}
|
||||
|
||||
/**
|
||||
* This updates all the results for the getTopPlayedResults so that we can get an
|
||||
* accurate list of the top played results
|
||||
*/
|
||||
private synchronized void updateResults() {
|
||||
if (mDatabaseUpdated) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
|
||||
database.beginTransaction();
|
||||
|
||||
int oldestWeekWeCareAbout = mNumberOfWeeksSinceEpoch - NUM_WEEKS + 1;
|
||||
// delete rows we don't care about anymore
|
||||
database.delete(SongPlayCountColumns.NAME, SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX
|
||||
+ " < " + oldestWeekWeCareAbout, null);
|
||||
|
||||
// get the remaining rows
|
||||
Cursor cursor = database.query(SongPlayCountColumns.NAME,
|
||||
new String[]{SongPlayCountColumns.ID},
|
||||
null, null, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
// for each row, update it
|
||||
do {
|
||||
updateExistingRow(database, cursor.getLong(0), false);
|
||||
} while (cursor.moveToNext());
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
mDatabaseUpdated = true;
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param songId The song Id to remove.
|
||||
*/
|
||||
public void removeItem(final long songId) {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
deleteEntry(database, String.valueOf(songId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the entry
|
||||
*
|
||||
* @param database database to use
|
||||
* @param stringId id to delete
|
||||
*/
|
||||
private void deleteEntry(@NonNull final SQLiteDatabase database, final String stringId) {
|
||||
database.delete(SongPlayCountColumns.NAME, WHERE_ID_EQUALS, new String[]{stringId});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the score of the song given the play counts
|
||||
*
|
||||
* @param playCounts an array of the # of times a song has been played for each week
|
||||
* where playCounts[N] is the # of times it was played N weeks ago
|
||||
* @return the score
|
||||
*/
|
||||
private static float calculateScore(@Nullable final int[] playCounts) {
|
||||
if (playCounts == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float score = 0;
|
||||
for (int i = 0; i < Math.min(playCounts.length, NUM_WEEKS); i++) {
|
||||
score += playCounts[i] * getScoreMultiplierForWeek(i);
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column name for each week #
|
||||
*
|
||||
* @param week number
|
||||
* @return the column name
|
||||
*/
|
||||
@NonNull
|
||||
private static String getColumnNameForWeek(final int week) {
|
||||
return SongPlayCountColumns.WEEK_PLAY_COUNT + String.valueOf(week);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the score multiplier for each week
|
||||
*
|
||||
* @param week number
|
||||
* @return the multiplier to apply
|
||||
*/
|
||||
private static float getScoreMultiplierForWeek(final int week) {
|
||||
return sInterpolator.getInterpolation(1 - (week / (float) NUM_WEEKS)) * INTERPOLATOR_HEIGHT
|
||||
+ INTERPOLATOR_BASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* For some performance gain, return a static value for the column index for a week
|
||||
* WARNING: This function assumes you have selected all columns for it to work
|
||||
*
|
||||
* @param week number
|
||||
* @return column index of that week
|
||||
*/
|
||||
private static int getColumnIndexForWeek(final int week) {
|
||||
// ID, followed by the weeks columns
|
||||
return 1 + week;
|
||||
}
|
||||
|
||||
public interface SongPlayCountColumns {
|
||||
|
||||
String NAME = "song_play_count";
|
||||
|
||||
String ID = "song_id";
|
||||
|
||||
String WEEK_PLAY_COUNT = "week";
|
||||
|
||||
String LAST_UPDATED_WEEK_INDEX = "week_index";
|
||||
|
||||
String PLAY_COUNT_SCORE = "play_count_score";
|
||||
}
|
||||
}
|
||||
|
|
@ -77,8 +77,10 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
|||
final Context context = (Context) msg.obj;
|
||||
startService(context, command);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
releaseWakeLockIfHandlerIdle();
|
||||
}
|
||||
};
|
||||
|
|
@ -103,8 +105,9 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
|||
final int action = event.getAction();
|
||||
|
||||
// fallback to system time if event time is not available
|
||||
final long eventTime = event.getEventTime() != 0 ?
|
||||
event.getEventTime() : System.currentTimeMillis();
|
||||
final long eventTime = event.getEventTime() != 0
|
||||
? event.getEventTime()
|
||||
: System.currentTimeMillis();
|
||||
|
||||
String command = null;
|
||||
switch (keycode) {
|
||||
|
|
@ -196,9 +199,8 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
|||
}
|
||||
|
||||
if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what);
|
||||
// Make sure we don't indefinitely hold the wake lock under any circumstances
|
||||
mWakeLock.acquire(10000);
|
||||
|
||||
mWakeLock.acquire(10000);
|
||||
mHandler.sendMessageDelayed(msg, delay);
|
||||
}
|
||||
|
||||
|
|
@ -210,6 +212,7 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
|||
|
||||
if (mWakeLock != null) {
|
||||
if (DEBUG) Log.v(TAG, "Releasing wake lock");
|
||||
|
||||
mWakeLock.release();
|
||||
mWakeLock = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, Media
|
|||
private MediaPlayer mNextMediaPlayer;
|
||||
|
||||
private Context context;
|
||||
|
||||
@Nullable
|
||||
private Playback.PlaybackCallbacks callbacks;
|
||||
|
||||
|
|
@ -46,6 +47,7 @@ public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, Media
|
|||
if (mIsInitialized) {
|
||||
setNextDataSource(null);
|
||||
}
|
||||
|
||||
return mIsInitialized;
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +62,7 @@ public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, Media
|
|||
if (context == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
player.reset();
|
||||
player.setOnPreparedListener(null);
|
||||
|
|
@ -68,17 +71,21 @@ public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, Media
|
|||
} else {
|
||||
player.setDataSource(path);
|
||||
}
|
||||
|
||||
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
player.prepare();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
player.setOnCompletionListener(this);
|
||||
player.setOnErrorListener(this);
|
||||
|
||||
final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
|
||||
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
|
||||
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
|
||||
intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC);
|
||||
|
||||
context.sendBroadcast(intent);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -94,6 +101,7 @@ public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, Media
|
|||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mCurrentMediaPlayer.setNextMediaPlayer(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
|
@ -102,13 +110,16 @@ public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, Media
|
|||
Log.e(TAG, "Media player not initialized!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mNextMediaPlayer != null) {
|
||||
mNextMediaPlayer.release();
|
||||
mNextMediaPlayer = null;
|
||||
}
|
||||
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PreferenceUtil.getInstance(context).getGaplessPlayback()) {
|
||||
mNextMediaPlayer = new MediaPlayer();
|
||||
mNextMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);
|
||||
|
|
@ -161,6 +172,7 @@ public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, Media
|
|||
@Override
|
||||
public void release() {
|
||||
stop();
|
||||
|
||||
mCurrentMediaPlayer.release();
|
||||
if (mNextMediaPlayer != null) {
|
||||
mNextMediaPlayer.release();
|
||||
|
|
@ -264,11 +276,9 @@ public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, Media
|
|||
mCurrentMediaPlayer = mNextMediaPlayer;
|
||||
mIsInitialized = true;
|
||||
mNextMediaPlayer = null;
|
||||
if (callbacks != null)
|
||||
callbacks.onTrackWentToNext();
|
||||
if (callbacks != null) callbacks.onTrackWentToNext();
|
||||
} else {
|
||||
if (callbacks != null)
|
||||
callbacks.onTrackEnded();
|
||||
if (callbacks != null) callbacks.onTrackEnded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,12 +140,14 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
private MediaSessionCompat mediaSession;
|
||||
private PowerManager.WakeLock wakeLock;
|
||||
private PlaybackHandler playerHandler;
|
||||
|
||||
private final AudioManager.OnAudioFocusChangeListener audioFocusListener = new AudioManager.OnAudioFocusChangeListener() {
|
||||
@Override
|
||||
public void onAudioFocusChange(final int focusChange) {
|
||||
playerHandler.obtainMessage(FOCUS_CHANGE, focusChange, 0).sendToTarget();
|
||||
}
|
||||
};
|
||||
|
||||
private QueueSaveHandler queueSaveHandler;
|
||||
private HandlerThread musicPlayerHandlerThread;
|
||||
private HandlerThread queueSaveHandlerThread;
|
||||
|
|
@ -153,6 +155,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
private ThrottledSeekHandler throttledSeekHandler;
|
||||
private boolean becomingNoisyReceiverRegistered;
|
||||
private IntentFilter becomingNoisyReceiverIntentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
|
||||
|
||||
private final BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, @NonNull Intent intent) {
|
||||
|
|
@ -161,6 +164,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
private ContentObserver mediaStoreObserver;
|
||||
private boolean notHandledMetaChangedForCurrentTrack;
|
||||
|
||||
|
|
@ -200,6 +204,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
|
||||
mediaStoreObserver = new MediaStoreObserver(playerHandler);
|
||||
throttledSeekHandler = new ThrottledSeekHandler(playerHandler);
|
||||
|
||||
getContentResolver().registerContentObserver(
|
||||
MediaStore.Audio.Media.INTERNAL_CONTENT_URI, true, mediaStoreObserver);
|
||||
getContentResolver().registerContentObserver(
|
||||
|
|
@ -339,6 +344,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
unregisterReceiver(becomingNoisyReceiver);
|
||||
becomingNoisyReceiverRegistered = false;
|
||||
}
|
||||
|
||||
mediaSession.setActive(false);
|
||||
quit();
|
||||
releaseResources();
|
||||
|
|
@ -400,6 +406,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
private void restoreState() {
|
||||
shuffleMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_SHUFFLE_MODE, 0);
|
||||
repeatMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_REPEAT_MODE, 0);
|
||||
|
||||
handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED);
|
||||
handleAndSendChangeInternal(REPEAT_MODE_CHANGED);
|
||||
|
||||
|
|
@ -411,6 +418,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
if (!queuesRestored && playingQueue.isEmpty()) {
|
||||
List<Song> restoredQueue = QueueStore.getInstance(this).getSavedPlayingQueue();
|
||||
List<Song> restoredOriginalQueue = QueueStore.getInstance(this).getSavedOriginalPlayingQueue();
|
||||
|
||||
int restoredPosition = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION, -1);
|
||||
int restoredPositionInTrack = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION_IN_TRACK, -1);
|
||||
|
||||
|
|
@ -429,6 +437,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
sendChangeInternal(QUEUE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
queuesRestored = true;
|
||||
}
|
||||
|
||||
|
|
@ -448,12 +457,14 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
} else {
|
||||
musicPlayerHandlerThread.quit();
|
||||
}
|
||||
|
||||
queueSaveHandler.removeCallbacksAndMessages(null);
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
queueSaveHandlerThread.quitSafely();
|
||||
} else {
|
||||
queueSaveHandlerThread.quit();
|
||||
}
|
||||
|
||||
playback.release();
|
||||
playback = null;
|
||||
mediaSession.release();
|
||||
|
|
@ -527,6 +538,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
} else {
|
||||
playingNotification = new PlayingNotificationImpl();
|
||||
}
|
||||
|
||||
playingNotification.init(this);
|
||||
}
|
||||
|
||||
|
|
@ -540,8 +552,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
mediaSession.setPlaybackState(
|
||||
new PlaybackStateCompat.Builder()
|
||||
.setActions(MEDIA_SESSION_ACTIONS)
|
||||
.setState(isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED,
|
||||
getPosition(), 1)
|
||||
.setState(isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, getPosition(), 1)
|
||||
.build());
|
||||
}
|
||||
|
||||
|
|
@ -865,11 +876,13 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
|||
if (!songs.isEmpty()) {
|
||||
startPosition = new Random().nextInt(songs.size());
|
||||
}
|
||||
|
||||
openQueue(songs, startPosition, false);
|
||||
setShuffleMode(shuffleMode);
|
||||
} else {
|
||||
openQueue(songs, 0, false);
|
||||
}
|
||||
|
||||
play();
|
||||
} else {
|
||||
Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show();
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ import com.kabouzeid.gramophone.R;
|
|||
import com.kabouzeid.gramophone.util.ImageUtil;
|
||||
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class AppShortcutIconGenerator {
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,6 @@ import com.kabouzeid.gramophone.shortcuts.shortcuttype.FrequentShortcutType;
|
|||
import com.kabouzeid.gramophone.model.Playlist;
|
||||
import com.kabouzeid.gramophone.service.MusicService;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
|
||||
public class AppShortcutLauncherActivity extends Activity {
|
||||
public static final String KEY_SHORTCUT_TYPE = "com.kabouzeid.gramophone.shortcuts.ShortcutType";
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@ import com.kabouzeid.gramophone.shortcuts.shortcuttype.FrequentShortcutType;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public class DynamicShortcutManager {
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ import android.os.Bundle;
|
|||
|
||||
import com.kabouzeid.gramophone.shortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public abstract class BaseShortcutType {
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ import com.kabouzeid.gramophone.R;
|
|||
import com.kabouzeid.gramophone.shortcuts.AppShortcutIconGenerator;
|
||||
import com.kabouzeid.gramophone.shortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class FrequentShortcutType extends BaseShortcutType {
|
||||
public FrequentShortcutType(Context context) {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ import com.kabouzeid.gramophone.R;
|
|||
import com.kabouzeid.gramophone.shortcuts.AppShortcutIconGenerator;
|
||||
import com.kabouzeid.gramophone.shortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class LatestShortcutType extends BaseShortcutType {
|
||||
public LatestShortcutType(Context context) {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ import com.kabouzeid.gramophone.R;
|
|||
import com.kabouzeid.gramophone.shortcuts.AppShortcutIconGenerator;
|
||||
import com.kabouzeid.gramophone.shortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class ShuffleShortcutType extends BaseShortcutType {
|
||||
public ShuffleShortcutType(Context context) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import android.widget.TextView;
|
|||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.SearchAdapter;
|
||||
import com.kabouzeid.gramophone.interfaces.LoaderIds;
|
||||
import com.kabouzeid.gramophone.interfaces.MediaCallback;
|
||||
import com.kabouzeid.gramophone.model.Album;
|
||||
import com.kabouzeid.gramophone.model.Artist;
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ import android.view.View;
|
|||
import com.kabouzeid.gramophone.interfaces.MusicServiceEventListener;
|
||||
import com.kabouzeid.gramophone.ui.activities.base.AbsMusicServiceActivity;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class AbsMusicServiceFragment extends Fragment implements MusicServiceEventListener {
|
||||
private AbsMusicServiceActivity activity;
|
||||
|
||||
|
|
@ -45,41 +42,33 @@ public class AbsMusicServiceFragment extends Fragment implements MusicServiceEve
|
|||
|
||||
@Override
|
||||
public void onPlayingMetaChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayStateChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaStoreChanged() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,7 @@ import androidx.fragment.app.Fragment;
|
|||
|
||||
import com.kabouzeid.gramophone.ui.activities.MainActivity;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public abstract class AbsMainActivityFragment extends Fragment {
|
||||
|
||||
public MainActivity getMainActivity() {
|
||||
return (MainActivity) getActivity();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.kabouzeid.gramophone.ui.fragments.mainactivity.library;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
|
@ -207,6 +206,7 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
|
|||
menu.removeItem(R.id.action_colored_footers);
|
||||
menu.removeItem(R.id.action_sort_order);
|
||||
}
|
||||
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
ToolbarContentTintHelper.handleOnCreateOptionsMenu(getActivity(), toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(toolbar));
|
||||
|
|
@ -234,6 +234,7 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
|
|||
if (handleGridSizeMenuItem(absLibraryRecyclerViewCustomGridSizeFragment, item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handleSortOrderMenuItem(absLibraryRecyclerViewCustomGridSizeFragment, item)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -251,6 +252,7 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
|
|||
startActivity(new Intent(getActivity(), SearchActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
|
@ -330,12 +332,14 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
|
|||
gridSize = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gridSize > 0) {
|
||||
item.setChecked(true);
|
||||
fragment.setAndSaveGridSize(gridSize);
|
||||
toolbar.getMenu().findItem(R.id.action_colored_footers).setEnabled(fragment.canUsePalette());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -434,6 +438,7 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
|
|||
cab.finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,17 +6,7 @@ import androidx.loader.app.LoaderManager;
|
|||
import com.kabouzeid.gramophone.ui.fragments.AbsMusicServiceFragment;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.library.LibraryFragment;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class AbsLibraryPagerFragment extends AbsMusicServiceFragment {
|
||||
|
||||
/* http://stackoverflow.com/a/2888433 */
|
||||
@Override
|
||||
public LoaderManager getLoaderManager() {
|
||||
return getParentFragment().getLoaderManager();
|
||||
}
|
||||
|
||||
public LibraryFragment getLibraryFragment() {
|
||||
return (LibraryFragment) getParentFragment();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ import android.view.View;
|
|||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.util.Util;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extends RecyclerView.Adapter, LM extends RecyclerView.LayoutManager> extends AbsLibraryPagerRecyclerViewFragment<A, LM> {
|
||||
private int gridSize;
|
||||
private String sortOrder;
|
||||
|
|
@ -28,6 +25,7 @@ public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extend
|
|||
gridSize = loadGridSize();
|
||||
}
|
||||
}
|
||||
|
||||
return gridSize;
|
||||
}
|
||||
|
||||
|
|
@ -39,14 +37,12 @@ public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extend
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the palette should be used at all or not
|
||||
*/
|
||||
public final boolean usePalette() {
|
||||
if (!usePaletteInitialized) {
|
||||
usePalette = loadUsePalette();
|
||||
usePaletteInitialized = true;
|
||||
}
|
||||
|
||||
return usePalette;
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +50,7 @@ public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extend
|
|||
if (sortOrder == null) {
|
||||
sortOrder = loadSortOrder();
|
||||
}
|
||||
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
|
|
@ -65,6 +62,7 @@ public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extend
|
|||
} else {
|
||||
saveGridSize(gridSize);
|
||||
}
|
||||
|
||||
// only recreate the adapter and layout manager if the layout currentLayoutRes has changed
|
||||
if (oldLayoutRes != getItemLayoutRes()) {
|
||||
invalidateLayoutManager();
|
||||
|
|
@ -86,18 +84,10 @@ public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extend
|
|||
setSortOrder(sortOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the palette option should be available for the current item layout or not
|
||||
*/
|
||||
public boolean canUsePalette() {
|
||||
return getItemLayoutRes() == R.layout.item_grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to customize which item layout currentLayoutRes should be used. You might also want to override {@link #canUsePalette()} then.
|
||||
*
|
||||
* @see #getGridSize()
|
||||
*/
|
||||
@LayoutRes
|
||||
protected int getItemLayoutRes() {
|
||||
if (getGridSize() > getMaxGridSizeForList()) {
|
||||
|
|
@ -156,6 +146,7 @@ public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extend
|
|||
if (isLandscape()) {
|
||||
return getActivity().getResources().getInteger(R.integer.default_list_columns_land);
|
||||
}
|
||||
|
||||
return getActivity().getResources().getInteger(R.integer.default_list_columns);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView.Adapter, LM extends RecyclerView.LayoutManager> extends AbsLibraryPagerFragment implements OnOffsetChangedListener {
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class AlbumsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager> {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class ArtistsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager> {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.kabouzeid.gramophone.ui.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -8,19 +7,13 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.PlaylistAdapter;
|
||||
import com.kabouzeid.gramophone.interfaces.LoaderIds;
|
||||
import com.kabouzeid.gramophone.interfaces.MediaCallback;
|
||||
import com.kabouzeid.gramophone.model.Playlist;
|
||||
import com.kabouzeid.gramophone.util.QueryUtil;
|
||||
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class PlaylistsFragment extends AbsLibraryPagerRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager> {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
|
|
|
|||
|
|
@ -28,17 +28,16 @@ import butterknife.ButterKnife;
|
|||
import butterknife.Unbinder;
|
||||
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class MiniPlayerFragment extends AbsMusicServiceFragment implements MusicProgressViewUpdateHelper.Callback {
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
||||
@BindView(R.id.mini_player_title)
|
||||
TextView miniPlayerTitle;
|
||||
|
||||
@BindView(R.id.mini_player_play_pause_button)
|
||||
ImageView miniPlayerPlayPauseButton;
|
||||
|
||||
@BindView(R.id.progress_bar)
|
||||
MaterialProgressBar progressBar;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ public enum NowPlayingScreen {
|
|||
|
||||
@StringRes
|
||||
public final int titleRes;
|
||||
|
||||
@DrawableRes
|
||||
public final int drawableResId;
|
||||
public final int id;
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements ViewPager.OnPageChangeListener {
|
||||
|
||||
public static final int VISIBILITY_ANIM_DURATION = 300;
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class CardPlayerPlaybackControlsFragment extends AbsMusicServiceFragment implements MusicProgressViewUpdateHelper.Callback {
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
|
|||
if (slidingUpPanelLayout != null) {
|
||||
slidingUpPanelLayout.removePanelSlideListener(this);
|
||||
}
|
||||
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager.release();
|
||||
recyclerViewDragDropManager = null;
|
||||
|
|
@ -142,6 +143,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
|
|||
WrapperAdapterUtils.releaseAll(wrappedAdapter);
|
||||
wrappedAdapter = null;
|
||||
}
|
||||
|
||||
playingQueueAdapter = null;
|
||||
layoutManager = null;
|
||||
super.onDestroyView();
|
||||
|
|
@ -328,8 +330,8 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
|
|||
onPanelCollapsed(panel);
|
||||
break;
|
||||
case ANCHORED:
|
||||
//noinspection ConstantConditions
|
||||
slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); // this fixes a bug where the panel would get stuck for some reason
|
||||
// this fixes a bug where the panel would get stuck for some reason
|
||||
slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -432,6 +434,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
|
|||
SongShareDialog.create(getSong()).show(fragment.getFragmentManager(), "SONG_SHARE_DIALOG");
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onMenuItemClick(item);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -34,9 +34,6 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class FlatPlayerPlaybackControlsFragment extends AbsMusicServiceFragment implements MusicProgressViewUpdateHelper.Callback {
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
|
|
|||
|
|
@ -14,9 +14,6 @@ import com.kabouzeid.gramophone.ui.activities.ArtistDetailActivity;
|
|||
import com.kabouzeid.gramophone.ui.activities.GenreDetailActivity;
|
||||
import com.kabouzeid.gramophone.ui.activities.PlaylistDetailActivity;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class NavigationUtil {
|
||||
|
||||
public static void goToArtist(@NonNull final Activity activity, final String artistId, @Nullable Pair... sharedElements) {
|
||||
|
|
@ -24,7 +21,7 @@ public class NavigationUtil {
|
|||
intent.putExtra(ArtistDetailActivity.EXTRA_ARTIST_ID, artistId);
|
||||
|
||||
if (sharedElements != null && sharedElements.length > 0) {
|
||||
//noinspection unchecked
|
||||
// noinspection unchecked
|
||||
activity.startActivity(intent, ActivityOptionsCompat.makeSceneTransitionAnimation(activity, sharedElements).toBundle());
|
||||
} else {
|
||||
activity.startActivity(intent);
|
||||
|
|
@ -36,7 +33,7 @@ public class NavigationUtil {
|
|||
intent.putExtra(AlbumDetailActivity.EXTRA_ALBUM_ID, albumId);
|
||||
|
||||
if (sharedElements != null && sharedElements.length > 0) {
|
||||
//noinspection unchecked
|
||||
// noinspection unchecked
|
||||
activity.startActivity(intent, ActivityOptionsCompat.makeSceneTransitionAnimation(activity, sharedElements).toBundle());
|
||||
} else {
|
||||
activity.startActivity(intent);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import com.kabouzeid.gramophone.R;
|
|||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
|
||||
|
||||
public class ViewUtil {
|
||||
|
||||
public final static int PHONOGRAPH_ANIM_TIME = 1000;
|
||||
|
||||
public static Animator createBackgroundColorTransition(final View v, @ColorInt final int startColor, @ColorInt final int endColor) {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@ import android.os.Build;
|
|||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class HeightFitSquareLayout extends FrameLayout {
|
||||
|
||||
private boolean forceSquare = true;
|
||||
|
|
@ -32,7 +29,6 @@ public class HeightFitSquareLayout extends FrameLayout {
|
|||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
//noinspection SuspiciousNameCombination
|
||||
super.onMeasure(forceSquare ? heightMeasureSpec : widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@ import android.util.AttributeSet;
|
|||
import com.kabouzeid.appthemehelper.util.ATHUtil;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class IconImageView extends AppCompatImageView {
|
||||
public IconImageView(Context context) {
|
||||
super(context);
|
||||
|
|
|
|||
|
|
@ -22,18 +22,17 @@ import com.kabouzeid.gramophone.R;
|
|||
public class PlayPauseDrawable extends Drawable {
|
||||
private static final long PLAY_PAUSE_ANIMATION_DURATION = 250;
|
||||
|
||||
private static final Property<PlayPauseDrawable, Float> PROGRESS =
|
||||
new Property<PlayPauseDrawable, Float>(Float.class, "progress") {
|
||||
@Override
|
||||
public Float get(@NonNull PlayPauseDrawable d) {
|
||||
return d.getProgress();
|
||||
}
|
||||
private static final Property<PlayPauseDrawable, Float> PROGRESS = new Property<PlayPauseDrawable, Float>(Float.class, "progress") {
|
||||
@Override
|
||||
public Float get(@NonNull PlayPauseDrawable d) {
|
||||
return d.getProgress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(@NonNull PlayPauseDrawable d, Float value) {
|
||||
d.setProgress(value);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void set(@NonNull PlayPauseDrawable d, Float value) {
|
||||
d.setProgress(value);
|
||||
}
|
||||
};
|
||||
|
||||
private final Path leftPauseBar = new Path();
|
||||
private final Path rightPauseBar = new Path();
|
||||
|
|
@ -77,13 +76,17 @@ public class PlayPauseDrawable extends Drawable {
|
|||
|
||||
// The current distance between the two pause bars.
|
||||
final float barDist = lerp(pauseBarDistance, 0f, progress);
|
||||
|
||||
// The current width of each pause bar.
|
||||
float rawBarWidth = lerp(pauseBarWidth, pauseBarHeight / 1.75f, progress);
|
||||
|
||||
// We have to round the bar width when finishing the progress to prevent the gap
|
||||
// that might occur onDraw because of a pixel is lost when casting float to int instead of rounding it.
|
||||
final float barWidth = progress == 1f ? Math.round(rawBarWidth) : rawBarWidth;
|
||||
|
||||
// The current position of the left pause bar's top left coordinate.
|
||||
final float firstBarTopLeft = lerp(0f, barWidth, progress);
|
||||
|
||||
// The current position of the right pause bar's top right coordinate.
|
||||
final float secondBarTopRight = lerp(2f * barWidth + barDist, barWidth + barDist, progress);
|
||||
|
||||
|
|
@ -136,6 +139,7 @@ public class PlayPauseDrawable extends Drawable {
|
|||
isPlay = !isPlay;
|
||||
}
|
||||
});
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ import android.view.WindowInsets;
|
|||
import android.widget.FrameLayout;
|
||||
|
||||
public class StatusBarMarginFrameLayout extends FrameLayout {
|
||||
|
||||
|
||||
public StatusBarMarginFrameLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
|
@ -28,6 +26,7 @@ public class StatusBarMarginFrameLayout extends FrameLayout {
|
|||
lp.topMargin = insets.getSystemWindowInsetTop();
|
||||
setLayoutParams(lp);
|
||||
}
|
||||
|
||||
return super.onApplyWindowInsets(insets);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import android.view.ViewGroup;
|
|||
import android.view.WindowInsets;
|
||||
|
||||
public class StatusBarView extends View {
|
||||
|
||||
public StatusBarView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
|
@ -28,7 +27,7 @@ public class StatusBarView extends View {
|
|||
lp.height = insets.getSystemWindowInsetTop();
|
||||
setLayoutParams(lp);
|
||||
}
|
||||
|
||||
return super.onApplyWindowInsets(insets);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@ import android.os.Build;
|
|||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class WidthFitSquareLayout extends FrameLayout {
|
||||
|
||||
private boolean forceSquare = true;
|
||||
|
|
@ -32,7 +29,6 @@ public class WidthFitSquareLayout extends FrameLayout {
|
|||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
//noinspection SuspiciousNameCombination
|
||||
super.onMeasure(widthMeasureSpec, forceSquare ? widthMeasureSpec : heightMeasureSpec);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,15 @@ public class BootReceiver extends BroadcastReceiver {
|
|||
public void onReceive(final Context context, Intent intent) {
|
||||
final AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
|
||||
|
||||
// Start music service if there are any existing widgets
|
||||
if (widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetBig.class)).length > 0 ||
|
||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetClassic.class)).length > 0 ||
|
||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetSmall.class)).length > 0 ||
|
||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetCard.class)).length > 0) {
|
||||
// start music service if there are any existing widgets
|
||||
if (widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetBig.class)).length > 0
|
||||
|| widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetClassic.class)).length > 0
|
||||
|| widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetSmall.class)).length > 0
|
||||
|| widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetCard.class)).length > 0) {
|
||||
final Intent serviceIntent = new Intent(context, MusicService.class);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // not allowed on Oreo
|
||||
|
||||
// not allowed on Oreo
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue