Before a now-playing display, find where the head unit tells what is playing, read only: the players Android reports, the active media sessions, and every media browser service with its song, CarPlay's (com.allgo.remoteui.mediabrowserservice) among them. The report is saved and sent like a signal recording (shared SignalRecorder.saveCopies). Also the findings of the first two recordings from the server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
89 lines
3.1 KiB
Java
89 lines
3.1 KiB
Java
package com.evsuite.abrp;
|
|
|
|
import java.util.Locale;
|
|
|
|
/**
|
|
* The words of {@link MediaProbe}'s report: Android's numbers for playback and audio states as
|
|
* names, and text from other apps made safe for one line. Android-free and unit-tested.
|
|
*/
|
|
final class MediaProbeText {
|
|
|
|
/** Longest text kept from another app (a title, an artist). */
|
|
static final int MAX_TEXT = 120;
|
|
|
|
private MediaProbeText() {}
|
|
|
|
/** Another app's text on one line: control characters out, at most {@link #MAX_TEXT}. */
|
|
static String clean(CharSequence text) {
|
|
if (text == null) return "(none)";
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int i = 0; i < text.length() && sb.length() < MAX_TEXT; i++) {
|
|
char c = text.charAt(i);
|
|
sb.append(Character.isISOControl(c) ? ' ' : c);
|
|
}
|
|
String s = sb.toString().trim();
|
|
if (text.length() > MAX_TEXT) s += "…";
|
|
return s.isEmpty() ? "(empty)" : s;
|
|
}
|
|
|
|
/** {@code android.media.session.PlaybackState} STATE_*. */
|
|
static String playbackState(int state) {
|
|
switch (state) {
|
|
case 0: return "none";
|
|
case 1: return "stopped";
|
|
case 2: return "paused";
|
|
case 3: return "playing";
|
|
case 4: return "fast forwarding";
|
|
case 5: return "rewinding";
|
|
case 6: return "buffering";
|
|
case 7: return "error";
|
|
case 8: return "connecting";
|
|
case 9: return "skipping to previous";
|
|
case 10: return "skipping to next";
|
|
case 11: return "skipping to queue item";
|
|
default: return "state " + state;
|
|
}
|
|
}
|
|
|
|
/** {@code android.media.AudioAttributes} USAGE_*. */
|
|
static String usage(int usage) {
|
|
switch (usage) {
|
|
case 0: return "unknown";
|
|
case 1: return "media";
|
|
case 2: return "voice call";
|
|
case 3: return "call signalling";
|
|
case 4: return "alarm";
|
|
case 5: return "notification";
|
|
case 6: return "ringtone";
|
|
case 7: case 8: case 9: case 10: return "notification (" + usage + ")";
|
|
case 11: return "accessibility";
|
|
case 12: return "navigation guidance";
|
|
case 13: return "sonification";
|
|
case 14: return "game";
|
|
case 15: return "virtual source";
|
|
case 16: return "assistant";
|
|
default: return "usage " + usage;
|
|
}
|
|
}
|
|
|
|
/** {@code android.media.AudioPlaybackConfiguration} PLAYER_STATE_*. */
|
|
static String playerState(int state) {
|
|
switch (state) {
|
|
case -1: return "unknown";
|
|
case 0: return "released";
|
|
case 1: return "idle";
|
|
case 2: return "started";
|
|
case 3: return "paused";
|
|
case 4: return "stopped";
|
|
default: return "state " + state;
|
|
}
|
|
}
|
|
|
|
/** A position or duration in milliseconds as m:ss; negative (unknown) as "?". */
|
|
static String duration(long ms) {
|
|
if (ms < 0) return "?";
|
|
long s = ms / 1000;
|
|
return String.format(Locale.US, "%d:%02d", s / 60, s % 60);
|
|
}
|
|
}
|