-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b2e49eb
commit 5842af6
Showing
22 changed files
with
878 additions
and
525 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
fermata/src/main/java/me/aap/fermata/action/Action.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package me.aap.fermata.action; | ||
|
||
import static android.media.AudioManager.ADJUST_LOWER; | ||
import static android.media.AudioManager.ADJUST_RAISE; | ||
import static android.media.AudioManager.ADJUST_TOGGLE_MUTE; | ||
import static android.media.AudioManager.FLAG_SHOW_UI; | ||
import static android.media.AudioManager.STREAM_MUSIC; | ||
import static android.os.SystemClock.uptimeMillis; | ||
import static java.util.Arrays.asList; | ||
import static java.util.Collections.unmodifiableList; | ||
|
||
import android.content.Context; | ||
import android.media.AudioManager; | ||
|
||
import androidx.annotation.Nullable; | ||
import androidx.annotation.StringRes; | ||
|
||
import java.util.List; | ||
|
||
import me.aap.fermata.R; | ||
import me.aap.fermata.media.service.MediaSessionCallback; | ||
import me.aap.fermata.ui.activity.MainActivityDelegate; | ||
import me.aap.utils.app.App; | ||
import me.aap.utils.ui.activity.ActivityDelegate; | ||
|
||
/** | ||
* @author Andrey Pavlenko | ||
*/ | ||
public enum Action { | ||
STOP(R.string.action_stop, m(MediaSessionCallback::onStop)), | ||
PLAY(R.string.action_play, m(MediaSessionCallback::onPlay)), | ||
PAUSE(R.string.action_pause, m(MediaSessionCallback::onPause)), | ||
PLAY_PAUSE(R.string.action_play_pause, m(cb -> { | ||
if (cb.isPlaying()) cb.onPause(); | ||
else cb.onPlay(); | ||
})), | ||
PREV(R.string.action_prev, m(MediaSessionCallback::onSkipToPrevious)), | ||
NEXT(R.string.action_next, m(MediaSessionCallback::onSkipToNext)), | ||
RW(R.string.action_rw, new RwFfHandler(false)), | ||
FF(R.string.action_ff, new RwFfHandler(true)), | ||
VOLUME_UP(R.string.action_vol_up, new VolumeHandler(ADJUST_RAISE)), | ||
VOLUME_DOWN(R.string.action_vol_down, new VolumeHandler(ADJUST_LOWER)), | ||
VOLUME_MUTE_UNMUTE(R.string.action_vol_mute_unmute, new VolumeHandler(ADJUST_TOGGLE_MUTE)), | ||
ACTIVATE_VOICE_CTRL(R.string.action_activate_voice_ctrl, | ||
m(cb -> cb.getAssistant().startVoiceAssistant())), | ||
MENU(R.string.action_menu, a(a -> a.getNavBarMediator().showMenu(a))), | ||
CP_MENU(R.string.action_cp_menu, a(a -> { | ||
var cp = a.getControlPanel(); | ||
if (cp.isActive()) cp.showMenu(); | ||
})), | ||
BACK_OR_EXIT(R.string.action_back_or_exit, a(ActivityDelegate::onBackPressed)), | ||
EXIT(R.string.action_exit, a(ActivityDelegate::finish)), | ||
NONE(R.string.action_none, m(cb -> {})), | ||
; | ||
|
||
private static final List<Action> all = unmodifiableList(asList(values())); | ||
|
||
@StringRes | ||
private final int name; | ||
private final Action.Handler handler; | ||
|
||
Action(int name, Action.Handler handler) { | ||
this.name = name; | ||
this.handler = handler; | ||
} | ||
|
||
@Nullable | ||
public static Action get(int ordinal) { | ||
return (ordinal >= 0) && (ordinal < all.size()) ? all.get(ordinal) : null; | ||
} | ||
|
||
public static List<Action> getAll() { | ||
return all; | ||
} | ||
|
||
@StringRes | ||
public int getName() { | ||
return name; | ||
} | ||
|
||
public Handler getHandler() { | ||
return handler; | ||
} | ||
|
||
private static Handler m(MediaHandler h) { | ||
return h; | ||
} | ||
|
||
private static Handler a(ActivityHandler h) { | ||
return h; | ||
} | ||
|
||
public interface Handler { | ||
void handle(MediaSessionCallback cb, @Nullable MainActivityDelegate a, long timestamp); | ||
} | ||
|
||
private interface MediaHandler extends Handler { | ||
void handle(MediaSessionCallback cb); | ||
|
||
@Override | ||
default void handle(MediaSessionCallback cb, @Nullable MainActivityDelegate a, | ||
long timestamp) { | ||
handle(cb); | ||
} | ||
} | ||
|
||
private interface ActivityHandler extends Handler { | ||
void handle(MainActivityDelegate a); | ||
|
||
@Override | ||
default void handle(MediaSessionCallback cb, @Nullable MainActivityDelegate a, | ||
long timestamp) { | ||
if (a != null) handle(a); | ||
} | ||
} | ||
|
||
private static final class VolumeHandler implements Handler { | ||
private final int direction; | ||
|
||
VolumeHandler(int direction) {this.direction = direction;} | ||
|
||
@Override | ||
public void handle(MediaSessionCallback cb, @Nullable MainActivityDelegate a, long timestamp) { | ||
var eng = cb.getEngine(); | ||
if ((eng != null) && eng.adjustVolume(direction)) return; | ||
var ctx = (a == null) ? App.get() : a.getContext(); | ||
var amgr = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE); | ||
if (amgr != null) amgr.adjustStreamVolume(STREAM_MUSIC, direction, FLAG_SHOW_UI); | ||
} | ||
} | ||
|
||
private static final class RwFfHandler implements Handler { | ||
private final boolean ff; | ||
|
||
private RwFfHandler(boolean ff) {this.ff = ff;} | ||
|
||
@Override | ||
public void handle(MediaSessionCallback cb, @Nullable MainActivityDelegate a, long timestamp) { | ||
cb.rewindFastForward(ff, (int) ((uptimeMillis() - timestamp) / 1000)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package me.aap.fermata.action; | ||
|
||
import static java.util.Arrays.asList; | ||
import static java.util.Collections.unmodifiableList; | ||
|
||
import android.view.KeyEvent; | ||
|
||
import androidx.annotation.Nullable; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import me.aap.fermata.ui.activity.MainActivityPrefs; | ||
import me.aap.utils.function.IntSupplier; | ||
import me.aap.utils.pref.PreferenceStore; | ||
|
||
/** | ||
* @author Andrey Pavlenko | ||
*/ | ||
public enum Key { | ||
MEDIA_STOP(KeyEvent.KEYCODE_MEDIA_STOP, Action.STOP), | ||
MEDIA_PLAY(KeyEvent.KEYCODE_MEDIA_PLAY, Action.PLAY), | ||
MEDIA_PAUSE(KeyEvent.KEYCODE_MEDIA_PAUSE, Action.PAUSE), | ||
MEDIA_PLAY_PAUSE(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, Action.PLAY_PAUSE), | ||
MEDIA_PREVIOUS(KeyEvent.KEYCODE_MEDIA_PREVIOUS, Action.PREV), | ||
MEDIA_NEXT(KeyEvent.KEYCODE_MEDIA_NEXT, Action.NEXT), | ||
MEDIA_REWIND(KeyEvent.KEYCODE_MEDIA_REWIND, Action.RW, Action.RW, Action.RW), | ||
MEDIA_FAST_FORWARD(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, Action.FF, Action.FF, Action.FF), | ||
VOLUME_UP(KeyEvent.KEYCODE_VOLUME_UP, Action.VOLUME_UP), | ||
VOLUME_DOWN(KeyEvent.KEYCODE_VOLUME_DOWN, Action.VOLUME_DOWN), | ||
HEADSETHOOK(KeyEvent.KEYCODE_HEADSETHOOK, Action.PLAY_PAUSE, Action.NEXT, | ||
Action.ACTIVATE_VOICE_CTRL), | ||
SEARCH(KeyEvent.KEYCODE_SEARCH, Action.ACTIVATE_VOICE_CTRL), | ||
BACK(KeyEvent.KEYCODE_BACK, Action.BACK_OR_EXIT), | ||
ESCAPE(KeyEvent.KEYCODE_ESCAPE, Action.BACK_OR_EXIT), | ||
DEL(KeyEvent.KEYCODE_DEL, Action.STOP), | ||
MENU(KeyEvent.KEYCODE_MENU, Action.MENU, Action.CP_MENU, Action.CP_MENU), | ||
M(KeyEvent.KEYCODE_M, Action.MENU, Action.CP_MENU, Action.CP_MENU), | ||
P(KeyEvent.KEYCODE_P, Action.PLAY_PAUSE), | ||
S(KeyEvent.KEYCODE_S, Action.STOP), | ||
X(KeyEvent.KEYCODE_X, Action.EXIT); | ||
|
||
private static final Map<Integer, Key> keys = new HashMap<>(); | ||
|
||
private static final List<Key> all = unmodifiableList(asList(values())); | ||
private static final PrefsListener listener = new PrefsListener(); | ||
|
||
static { | ||
for (var k : all) keys.put(k.code, k); | ||
MainActivityPrefs.get().addBroadcastListener(listener); | ||
} | ||
|
||
private final int code; | ||
private final boolean media; | ||
private final PreferenceStore.Pref<IntSupplier> actionPref; | ||
private final PreferenceStore.Pref<IntSupplier> dblActionPref; | ||
private final PreferenceStore.Pref<IntSupplier> longActionPref; | ||
@Nullable | ||
private Action.Handler clickHandler; | ||
@Nullable | ||
private Action.Handler dblClickHandler; | ||
@Nullable | ||
private Action.Handler longClickHandler; | ||
|
||
Key(int code, Action action) { | ||
this(code, action, action, action); | ||
} | ||
|
||
Key(int code, Action action, Action dblAction, Action longAction) { | ||
this.code = code; | ||
var name = name(); | ||
media = name.startsWith("MEDIA_") || name.startsWith("VOLUME_"); | ||
actionPref = | ||
PreferenceStore.Pref.i("KEY_ACTION_" + name, action.ordinal()).withInheritance(false); | ||
dblActionPref = PreferenceStore.Pref.i("KEY_ACTION_DBL_" + name, dblAction.ordinal()) | ||
.withInheritance(false); | ||
longActionPref = PreferenceStore.Pref.i("KEY_ACTION_LONG_" + name, longAction.ordinal()) | ||
.withInheritance(false); | ||
} | ||
|
||
@Nullable | ||
public static Key get(int code) { | ||
return keys.get(code); | ||
} | ||
|
||
public static List<Key> getAll() { | ||
return all; | ||
} | ||
|
||
public static PreferenceStore getPrefs() { | ||
return MainActivityPrefs.get(); | ||
} | ||
|
||
public PreferenceStore.Pref<IntSupplier> getActionPref() { | ||
return actionPref; | ||
} | ||
|
||
public PreferenceStore.Pref<IntSupplier> getDblActionPref() { | ||
return dblActionPref; | ||
} | ||
|
||
public PreferenceStore.Pref<IntSupplier> getLongActionPref() { | ||
return longActionPref; | ||
} | ||
|
||
@Nullable | ||
public Action.Handler getClickHandler() { | ||
if (clickHandler != null) return clickHandler; | ||
var a = Action.get(getPrefs().getIntPref(actionPref)); | ||
return (a == null) ? null : (clickHandler = a.getHandler()); | ||
} | ||
|
||
@Nullable | ||
public Action.Handler getDblClickHandler() { | ||
if (dblClickHandler != null) return dblClickHandler; | ||
var a = Action.get(getPrefs().getIntPref(dblActionPref)); | ||
return (a == null) ? null : (dblClickHandler = a.getHandler()); | ||
} | ||
|
||
@Nullable | ||
public Action.Handler getLongClickHandler() { | ||
if (longClickHandler != null) return longClickHandler; | ||
var a = Action.get(getPrefs().getIntPref(longActionPref)); | ||
return (a == null) ? null : (longClickHandler = a.getHandler()); | ||
} | ||
|
||
public boolean isMedia() { | ||
return media; | ||
} | ||
|
||
public static final class PrefsListener implements PreferenceStore.Listener { | ||
|
||
@Override | ||
public void onPreferenceChanged(PreferenceStore store, List<PreferenceStore.Pref<?>> prefs) { | ||
for (var p : prefs) { | ||
if (p.getName().startsWith("KEY_ACTION_")) { | ||
for (var k : Key.all) { | ||
k.clickHandler = null; | ||
k.dblClickHandler = null; | ||
k.longClickHandler = null; | ||
} | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.