clean up playback interface and a few other classes

This commit is contained in:
dkanada 2020-05-23 11:01:55 +09:00
commit 7edf0c85fa
12 changed files with 50 additions and 242 deletions

View file

@ -68,7 +68,6 @@ import java.util.List;
* complete} * complete}
*/ */
public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter { public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
public static final String TAG = CustomFragmentStatePagerAdapter.class.getSimpleName(); public static final String TAG = CustomFragmentStatePagerAdapter.class.getSimpleName();
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
@ -83,9 +82,6 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
mFragmentManager = fm; mFragmentManager = fm;
} }
/**
* Return the Fragment associated with a specified position.
*/
public abstract Fragment getItem(int position); public abstract Fragment getItem(int position);
@Override @Override
@ -117,9 +113,11 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
fragment.setInitialSavedState(fss); fragment.setInitialSavedState(fss);
} }
} }
while (mFragments.size() <= position) { while (mFragments.size() <= position) {
mFragments.add(null); mFragments.add(null);
} }
fragment.setMenuVisibility(false); fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false); fragment.setUserVisibleHint(false);
mFragments.set(position, fragment); mFragments.set(position, fragment);
@ -135,11 +133,13 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
if (mCurTransaction == null) { if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction(); mCurTransaction = mFragmentManager.beginTransaction();
} }
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment) object).getView()); + " v=" + ((Fragment) object).getView());
while (mSavedState.size() <= position) { while (mSavedState.size() <= position) {
mSavedState.add(null); mSavedState.add(null);
} }
mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment)); mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
mFragments.set(position, null); mFragments.set(position, null);
@ -158,6 +158,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
fragment.setMenuVisibility(true); fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true); fragment.setUserVisibleHint(true);
} }
mCurrentPrimaryItem = fragment; mCurrentPrimaryItem = fragment;
} }
} }
@ -185,6 +186,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
mSavedState.toArray(fss); mSavedState.toArray(fss);
state.putParcelableArray("states", fss); state.putParcelableArray("states", fss);
} }
for (int i = 0; i < mFragments.size(); i++) { for (int i = 0; i < mFragments.size(); i++) {
Fragment f = mFragments.get(i); Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) { if (f != null && f.isAdded()) {
@ -195,6 +197,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
mFragmentManager.putFragment(state, key, f); mFragmentManager.putFragment(state, key, f);
} }
} }
return state; return state;
} }
@ -211,6 +214,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
mSavedState.add((Fragment.SavedState) fs); mSavedState.add((Fragment.SavedState) fs);
} }
} }
Iterable<String> keys = bundle.keySet(); Iterable<String> keys = bundle.keySet();
for (String key : keys) { for (String key : keys) {
if (key.startsWith("f")) { if (key.startsWith("f")) {
@ -234,6 +238,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
if (position < mFragments.size() && position >= 0) { if (position < mFragments.size() && position >= 0) {
return mFragments.get(position); return mFragments.get(position);
} }
return null; return null;
} }
} }

View file

@ -1,89 +0,0 @@
package com.dkanada.gramophone.misc;
import android.app.Dialog;
import android.content.Context;
import android.os.Handler;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.ref.WeakReference;
public abstract class DialogAsyncTask<Params, Progress, Result> extends WeakContextAsyncTask<Params, Progress, Result> {
private final int delay;
private WeakReference<Dialog> dialogWeakReference;
private boolean supposedToBeDismissed;
public DialogAsyncTask(Context context) {
this(context, 0);
}
public DialogAsyncTask(Context context, int showDelay) {
super(context);
this.delay = showDelay;
dialogWeakReference = new WeakReference<>(null);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
if (delay > 0) {
new Handler().postDelayed(this::initAndShowDialog, delay);
} else {
initAndShowDialog();
}
}
private void initAndShowDialog() {
Context context = getContext();
if (!supposedToBeDismissed && context != null) {
Dialog dialog = createDialog(context);
dialogWeakReference = new WeakReference<>(dialog);
dialog.show();
}
}
@SuppressWarnings("unchecked")
@Override
protected void onProgressUpdate(Progress... values) {
super.onProgressUpdate(values);
Dialog dialog = getDialog();
if (dialog != null) {
onProgressUpdate(dialog, values);
}
}
@SuppressWarnings("unchecked")
protected void onProgressUpdate(@NonNull Dialog dialog, Progress... values) {
}
@Nullable
protected Dialog getDialog() {
return dialogWeakReference.get();
}
@Override
protected void onCancelled(Result result) {
super.onCancelled(result);
tryToDismiss();
}
@Override
protected void onPostExecute(Result result) {
super.onPostExecute(result);
tryToDismiss();
}
private void tryToDismiss() {
supposedToBeDismissed = true;
try {
Dialog dialog = getDialog();
if (dialog != null)
dialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
}
protected abstract Dialog createDialog(@NonNull Context context);
}

View file

@ -5,21 +5,17 @@ import android.animation.Animator;
public abstract class SimpleAnimatorListener implements Animator.AnimatorListener { public abstract class SimpleAnimatorListener implements Animator.AnimatorListener {
@Override @Override
public void onAnimationStart(Animator animation) { public void onAnimationStart(Animator animation) {
} }
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
} }
@Override @Override
public void onAnimationCancel(Animator animation) { public void onAnimationCancel(Animator animation) {
} }
@Override @Override
public void onAnimationRepeat(Animator animation) { public void onAnimationRepeat(Animator animation) {
} }
} }

View file

@ -1,20 +0,0 @@
package com.dkanada.gramophone.misc;
import android.content.Context;
import android.os.AsyncTask;
import androidx.annotation.Nullable;
import java.lang.ref.WeakReference;
public abstract class WeakContextAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
private WeakReference<Context> contextWeakReference;
public WeakContextAsyncTask(Context context) {
contextWeakReference = new WeakReference<>(context);
}
@Nullable
protected Context getContext() {
return contextWeakReference.get();
}
}

View file

@ -1,72 +0,0 @@
package com.dkanada.gramophone.misc;
import android.content.Context;
import androidx.loader.content.AsyncTaskLoader;
/**
* <a href="http://code.google.com/p/android/issues/detail?id=14944">Issue
* 14944</a>
*
* @author Alexander Blom
*/
public abstract class WrappedAsyncTaskLoader<D> extends AsyncTaskLoader<D> {
private D mData;
/**
* Constructor of <code>WrappedAsyncTaskLoader</code>
*
* @param context The {@link Context} to use.
*/
public WrappedAsyncTaskLoader(Context context) {
super(context);
}
/**
* {@inheritDoc}
*/
@Override
public void deliverResult(D data) {
if (!isReset()) {
this.mData = data;
super.deliverResult(data);
} else {
// An asynchronous query came in while the loader is stopped
}
}
/**
* {@inheritDoc}
*/
@Override
protected void onStartLoading() {
super.onStartLoading();
if (this.mData != null) {
deliverResult(this.mData);
} else if (takeContentChanged() || this.mData == null) {
forceLoad();
}
}
/**
* {@inheritDoc}
*/
@Override
protected void onStopLoading() {
super.onStopLoading();
// Attempt to cancel the current load task if possible
cancelLoad();
}
/**
* {@inheritDoc}
*/
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
this.mData = null;
}
}

View file

@ -46,7 +46,6 @@ public class MultiPlayer implements Playback {
private boolean isReady = false; private boolean isReady = false;
private boolean isPlaying = false; private boolean isPlaying = false;
private boolean isNew = false; private boolean isNew = false;
private boolean isFirst = true;
private ExoPlayer.EventListener eventListener = new ExoPlayer.EventListener() { private ExoPlayer.EventListener eventListener = new ExoPlayer.EventListener() {
@Override @Override
@ -118,7 +117,7 @@ public class MultiPlayer implements Playback {
} }
@Override @Override
public void setNextDataSource(@Nullable final String path) { public void queueDataSource(@Nullable final String path) {
if (context == null) { if (context == null) {
return; return;
} }
@ -151,11 +150,7 @@ public class MultiPlayer implements Playback {
} }
mediaSource.addMediaSource(source); mediaSource.addMediaSource(source);
if (!isFirst && next) { if (next) start();
start();
}
isFirst = false;
} }
}); });
} }
@ -171,7 +166,7 @@ public class MultiPlayer implements Playback {
} }
@Override @Override
public boolean start() { public void start() {
isPlaying = true; isPlaying = true;
exoPlayer.setPlayWhenReady(true); exoPlayer.setPlayWhenReady(true);
@ -179,8 +174,6 @@ public class MultiPlayer implements Playback {
callbacks.onTrackStarted(); callbacks.onTrackStarted();
isNew = false; isNew = false;
} }
return true;
} }
@Override @Override
@ -190,10 +183,9 @@ public class MultiPlayer implements Playback {
} }
@Override @Override
public boolean pause() { public void pause() {
isPlaying = false; isPlaying = false;
exoPlayer.setPlayWhenReady(false); exoPlayer.setPlayWhenReady(false);
return true;
} }
@Override @Override
@ -220,8 +212,7 @@ public class MultiPlayer implements Playback {
} }
@Override @Override
public boolean setVolume(float volume) { public void setVolume(float volume) {
exoPlayer.setVolume(volume); exoPlayer.setVolume(volume);
return true;
} }
} }

View file

@ -218,6 +218,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
if (audioManager == null) { if (audioManager == null) {
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
} }
return audioManager; return audioManager;
} }
@ -422,7 +423,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
this.playingQueue = restoredQueue; this.playingQueue = restoredQueue;
position = restoredPosition; position = restoredPosition;
openCurrent(); openCurrent(true);
if (restoredPositionInTrack > 0) seek(restoredPositionInTrack); if (restoredPositionInTrack > 0) seek(restoredPositionInTrack);
@ -471,20 +472,27 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
synchronized (this) { synchronized (this) {
this.position = position; this.position = position;
openCurrent(); openCurrent(false);
notifyChange(META_CHANGED); notifyChange(META_CHANGED);
notHandledMetaChangedForCurrentTrack = false; notHandledMetaChangedForCurrentTrack = false;
} }
} }
private void openCurrent() { private void openCurrent(boolean queue) {
synchronized (this) { synchronized (this) {
// current song will be null when queue is cleared // current song will be null when queue is cleared
if (getCurrentSong() == null) return; if (getCurrentSong() == null) return;
if (queue) {
// restore queue from database
playback.queueDataSource(getTrackUri(getCurrentSong()));
} else {
// set current song and start playback
playback.setDataSource(getTrackUri(getCurrentSong())); playback.setDataSource(getTrackUri(getCurrentSong()));
} }
} }
}
private void prepareNext() { private void prepareNext() {
playerHandler.removeMessages(PREPARE_NEXT); playerHandler.removeMessages(PREPARE_NEXT);
@ -494,7 +502,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private void prepareNextImpl() { private void prepareNextImpl() {
synchronized (this) { synchronized (this) {
nextPosition = getNextPosition(false); nextPosition = getNextPosition(false);
playback.setNextDataSource(getTrackUri(getSongAt(nextPosition))); playback.queueDataSource(getTrackUri(getSongAt(nextPosition)));
} }
} }

View file

@ -1,31 +1,29 @@
package com.dkanada.gramophone.service.playback; package com.dkanada.gramophone.service.playback;
import androidx.annotation.Nullable;
public interface Playback { public interface Playback {
void setDataSource(String path); void setDataSource(String path);
void setNextDataSource(@Nullable String path); void queueDataSource(String path);
void setCallbacks(PlaybackCallbacks callbacks); void setCallbacks(PlaybackCallbacks callbacks);
boolean isInitialized(); void start();
boolean start(); void pause();
void stop(); void stop();
boolean pause(); boolean isInitialized();
boolean isPlaying(); boolean isPlaying();
int duration();
int position(); int position();
int seek(int whereto); int duration();
boolean setVolume(float vol); int seek(int position);
void setVolume(float volume);
interface PlaybackCallbacks { interface PlaybackCallbacks {
void onTrackStarted(); void onTrackStarted();

View file

@ -18,9 +18,6 @@ import android.view.View;
import com.kabouzeid.appthemehelper.ThemeStore; import com.kabouzeid.appthemehelper.ThemeStore;
import com.dkanada.gramophone.R; import com.dkanada.gramophone.R;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public abstract class AbsBaseActivity extends AbsThemeActivity { public abstract class AbsBaseActivity extends AbsThemeActivity {
public static final int PERMISSION_REQUEST = 100; public static final int PERMISSION_REQUEST = 100;
@ -69,11 +66,11 @@ public abstract class AbsBaseActivity extends AbsThemeActivity {
showOverflowMenu(); showOverflowMenu();
return true; return true;
} }
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
protected void showOverflowMenu() { protected void showOverflowMenu() {
} }
@Nullable @Nullable
@ -107,6 +104,7 @@ public abstract class AbsBaseActivity extends AbsThemeActivity {
} }
} }
} }
return true; return true;
} }
@ -117,14 +115,14 @@ public abstract class AbsBaseActivity extends AbsThemeActivity {
for (int grantResult : grantResults) { for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) { if (grantResult != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(AbsBaseActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { if (ActivityCompat.shouldShowRequestPermissionRationale(AbsBaseActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
//User has deny from permission dialog // user has deny from permission dialog
Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(), Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(),
Snackbar.LENGTH_INDEFINITE) Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.action_grant, view -> requestPermissions()) .setAction(R.string.action_grant, view -> requestPermissions())
.setActionTextColor(ThemeStore.accentColor(this)) .setActionTextColor(ThemeStore.accentColor(this))
.show(); .show();
} else { } else {
// User has deny permission and checked never show permission dialog so you can redirect to Application settings page // user has deny permission and checked never show permission dialog so you can redirect to application settings page
Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(), Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(),
Snackbar.LENGTH_INDEFINITE) Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.action_settings, view -> { .setAction(R.string.action_settings, view -> {
@ -140,6 +138,7 @@ public abstract class AbsBaseActivity extends AbsThemeActivity {
return; return;
} }
} }
hadPermissions = true; hadPermissions = true;
onHasPermissionsChanged(true); onHasPermissionsChanged(true);
} }

View file

@ -21,9 +21,6 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements MusicServiceEventListener { public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements MusicServiceEventListener {
private final List<MusicServiceEventListener> mMusicServiceEventListeners = new ArrayList<>(); private final List<MusicServiceEventListener> mMusicServiceEventListeners = new ArrayList<>();
@ -206,7 +203,9 @@ public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements
protected void onHasPermissionsChanged(boolean hasPermissions) { protected void onHasPermissionsChanged(boolean hasPermissions) {
super.onHasPermissionsChanged(hasPermissions); super.onHasPermissionsChanged(hasPermissions);
Intent intent = new Intent(MusicService.MEDIA_STORE_CHANGED); Intent intent = new Intent(MusicService.MEDIA_STORE_CHANGED);
intent.putExtra("from_permissions_changed", true); // just in case we need to know this at some point
// just in case we need to know this at some point
intent.putExtra("from_permissions_changed", true);
sendBroadcast(intent); sendBroadcast(intent);
} }

View file

@ -28,12 +28,6 @@ import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
/**
* @author Karim Abou Zeid (kabouzeid)
* <p/>
* Do not use {@link #setContentView(int)}. Instead wrap your layout with
* {@link #wrapSlidingMusicPanel(int)} first and then return it in {@link #createContentView()}
*/
public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivity implements SlidingUpPanelLayout.PanelSlideListener, CardPlayerFragment.Callbacks { public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivity implements SlidingUpPanelLayout.PanelSlideListener, CardPlayerFragment.Callbacks {
@BindView(R.id.sliding_layout) @BindView(R.id.sliding_layout)
@ -57,7 +51,9 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
ButterKnife.bind(this); ButterKnife.bind(this);
currentNowPlayingScreen = PreferenceUtil.getInstance(this).getNowPlayingScreen(); currentNowPlayingScreen = PreferenceUtil.getInstance(this).getNowPlayingScreen();
Fragment fragment; // must implement AbsPlayerFragment
// must implement AbsPlayerFragment
Fragment fragment;
switch (currentNowPlayingScreen) { switch (currentNowPlayingScreen) {
case FLAT: case FLAT:
fragment = new FlatPlayerFragment(); fragment = new FlatPlayerFragment();

View file

@ -15,10 +15,6 @@ import com.dkanada.gramophone.R;
import com.dkanada.gramophone.util.PreferenceUtil; import com.dkanada.gramophone.util.PreferenceUtil;
import com.dkanada.gramophone.util.Util; import com.dkanada.gramophone.util.Util;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public abstract class AbsThemeActivity extends ATHToolbarActivity { public abstract class AbsThemeActivity extends ATHToolbarActivity {
@Override @Override
@ -29,11 +25,12 @@ public abstract class AbsThemeActivity extends ATHToolbarActivity {
} }
protected void setDrawUnderStatusbar() { protected void setDrawUnderStatusbar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Util.setAllowDrawUnderStatusBar(getWindow()); Util.setAllowDrawUnderStatusBar(getWindow());
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Util.setStatusBarTranslucent(getWindow()); Util.setStatusBarTranslucent(getWindow());
} }
}
/** /**
* This will set the color of the view with the id "status_bar" on KitKat and Lollipop. * This will set the color of the view with the id "status_bar" on KitKat and Lollipop.
@ -59,7 +56,7 @@ public abstract class AbsThemeActivity extends ATHToolbarActivity {
} }
public void setStatusbarColorAuto() { public void setStatusbarColorAuto() {
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat // we don't want to use status bar color because we are darkening the color on our own to support KitKat
setStatusbarColor(ThemeStore.primaryColor(this)); setStatusbarColor(ThemeStore.primaryColor(this));
} }