Skip to content

Commit d45ee67

Browse files
committed
add volume+/-
1 parent 385c589 commit d45ee67

11 files changed

Lines changed: 164 additions & 2 deletions

File tree

‎app/src/main/java/com/mg4/control/hardware/MG4Hardware.kt‎

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3702,6 +3702,125 @@ object MG4Hardware {
37023702
*/
37033703
fun mediaPlayPause(): Boolean = envoyerToucheMedia(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)
37043704

3705+
/**
3706+
* Monte ou descend le volume média d'un cran.
3707+
*
3708+
* Deux voies, dans cet ordre :
3709+
* 1. la voie **SAIC** ([getMediaVolume] / [setMediaVolume]) — la même que la baisse à
3710+
* l'ouverture de porte, déjà validée sur véhicule. C'est la seule qui donne un niveau
3711+
* ABSOLU, donc un log exploitable et un vrai respect des bornes ;
3712+
* 2. à défaut, `AudioManager.adjustStreamVolume`, la voie Android standard. Elle ne dit pas
3713+
* d'où l'on part, mais elle répond là où les managers SAIC ne sont pas liés — et elle
3714+
* affiche l'indicateur système, ce qui donne un retour visuel.
3715+
*
3716+
* Contrairement aux touches média, aucune des deux ne dépend d'une application : le volume
3717+
* est un réglage du véhicule. C'est pourquoi ces raccourcis fonctionnent quelle que soit la
3718+
* source, y compris là où « piste suivante » reste sans effet.
3719+
*/
3720+
fun mediaVolumeStep(delta: Int): Boolean {
3721+
val actuel = getMediaVolume()
3722+
val max = getMediaVolumeMax()
3723+
if (actuel >= 0 && max > 0) {
3724+
val cible = (actuel + delta).coerceIn(0, max)
3725+
if (cible == actuel) {
3726+
AppLogger.i(VOL_TAG, "volume déjà à la borne ($actuel/$max) — aucune écriture")
3727+
return true
3728+
}
3729+
AppLogger.i(VOL_TAG, "volume $actuel → $cible (max $max, voie SAIC)")
3730+
return setMediaVolume(cible)
3731+
}
3732+
val am = sAppContext?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
3733+
if (am == null) {
3734+
AppLogger.w(VOL_TAG, "volume : ni voie SAIC ni AudioManager — aucune action")
3735+
return false
3736+
}
3737+
return try {
3738+
am.adjustStreamVolume(
3739+
AudioManager.STREAM_MUSIC,
3740+
if (delta > 0) AudioManager.ADJUST_RAISE else AudioManager.ADJUST_LOWER,
3741+
AudioManager.FLAG_SHOW_UI
3742+
)
3743+
AppLogger.i(VOL_TAG, "volume ${if (delta > 0) "+1" else "-1"} " +
3744+
"(voie Android — niveau SAIC illisible, actuel=$actuel max=$max)")
3745+
true
3746+
} catch (e: Exception) {
3747+
AppLogger.w(VOL_TAG, "volume : ${(e.cause ?: e).message}")
3748+
false
3749+
}
3750+
}
3751+
3752+
/**
3753+
* Sonde média, LECTURE SEULE — elle n'envoie aucune commande.
3754+
*
3755+
* Elle existe pour trancher la seule question qui compte quand une touche média reste sans
3756+
* effet : **la commande n'est-elle pas partie, ou est-elle partie sans destinataire ?** Vu
3757+
* de l'utilisateur les deux cas sont identiques, et `dispatchMediaKeyEvent` ne rend rien.
3758+
*
3759+
* Trois informations, de la plus sûre à la plus révélatrice :
3760+
* • `isMusicActive` — quelque chose joue-t-il ;
3761+
* • les flux audio actifs et, si le système le laisse voir, l'application qui les produit ;
3762+
* • les **sessions média**. C'est le point décisif : `dispatchMediaKeyEvent` ne peut
3763+
* atteindre qu'une session. S'il n'y en a aucune, aucune touche média n'aboutira jamais,
3764+
* quel que soit le code envoyé — il faudra alors une autre voie.
3765+
*/
3766+
fun runMediaDiag() {
3767+
val ctx = sAppContext ?: return
3768+
val am = ctx.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
3769+
if (am == null) {
3770+
AppLogger.w(MEDIA_TAG, "DIAG : AudioManager indisponible")
3771+
return
3772+
}
3773+
AppLogger.i(MEDIA_TAG, "── DIAG média ────────────────────────────────")
3774+
AppLogger.i(MEDIA_TAG, "lecture en cours (isMusicActive) = ${am.isMusicActive}")
3775+
3776+
// Qui produit du son. La liste est publique ; l'identité du client, elle, est masquée aux
3777+
// applications ordinaires — on la tente par réflexion, en app système.
3778+
try {
3779+
val configs = am.activePlaybackConfigurations
3780+
AppLogger.i(MEDIA_TAG, "flux audio actifs : ${configs.size}")
3781+
configs.forEachIndexed { i, c ->
3782+
val uid = runCatching {
3783+
c.javaClass.getMethod("getClientUid").invoke(c) as? Int
3784+
}.getOrNull()
3785+
val paquets = uid?.let {
3786+
runCatching { ctx.packageManager.getPackagesForUid(it)?.joinToString() }
3787+
.getOrNull()
3788+
}
3789+
AppLogger.i(MEDIA_TAG, " [$i] usage=${c.audioAttributes.usage} " +
3790+
"contenu=${c.audioAttributes.contentType} uid=${uid ?: "?"} " +
3791+
"paquet=${paquets ?: "inconnu"}")
3792+
}
3793+
} catch (e: Exception) {
3794+
AppLogger.w(MEDIA_TAG, "flux audio illisibles : ${(e.cause ?: e).message}")
3795+
}
3796+
3797+
try {
3798+
val msm = ctx.getSystemService("media_session")
3799+
?: throw IllegalStateException("MediaSessionManager absent")
3800+
val m = msm.javaClass.getMethod("getActiveSessions", ComponentName::class.java)
3801+
@Suppress("UNCHECKED_CAST")
3802+
val sessions = m.invoke(msm, null) as? List<Any>
3803+
AppLogger.i(MEDIA_TAG, "sessions média actives : ${sessions?.size ?: 0}")
3804+
sessions?.forEach { session ->
3805+
val pkg = runCatching {
3806+
session.javaClass.getMethod("getPackageName").invoke(session)
3807+
}.getOrNull()
3808+
AppLogger.i(MEDIA_TAG, " session : $pkg")
3809+
}
3810+
if (sessions.isNullOrEmpty()) {
3811+
AppLogger.w(MEDIA_TAG, "AUCUNE session : les touches média ne peuvent aboutir " +
3812+
"nulle part, la source ne passe pas par MediaSession")
3813+
}
3814+
} catch (e: Exception) {
3815+
val cause = e.cause ?: e
3816+
AppLogger.w(MEDIA_TAG, "sessions média illisibles : " +
3817+
"${cause.javaClass.simpleName} — ${cause.message} " +
3818+
"(SecurityException = il manque MEDIA_CONTENT_CONTROL au manifest, " +
3819+
"et l'entrée correspondante dans permission-allowlist.txt)")
3820+
}
3821+
AppLogger.i(MEDIA_TAG, "──────────────────────────────────────────────")
3822+
}
3823+
37053824
/**
37063825
* Envoie une touche média au système, qui la remet à la session active.
37073826
*

‎app/src/main/java/com/mg4/control/service/MG4ControlService.kt‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ class MG4ControlService : Service() {
6565
ShortcutAction.HVAC_RECIRC_CYCLE,
6666
ShortcutAction.BRIGHTNESS_UP, ShortcutAction.BRIGHTNESS_DOWN,
6767
ShortcutAction.MEDIA_NEXT, ShortcutAction.MEDIA_PREVIOUS,
68-
ShortcutAction.MEDIA_PLAY_PAUSE
68+
ShortcutAction.MEDIA_PLAY_PAUSE,
69+
ShortcutAction.VOLUME_UP, ShortcutAction.VOLUME_DOWN
6970
)
7071

7172

@@ -534,6 +535,12 @@ class MG4ControlService : Service() {
534535
MG4Hardware.setDrowsinessSensitivity(suivant)
535536
}
536537

538+
ShortcutAction.VOLUME_UP, ShortcutAction.VOLUME_DOWN -> {
539+
val delta = if (action == ShortcutAction.VOLUME_UP) 1 else -1
540+
AppLogger.i(TAG, "SHORTCUT volume ${if (delta > 0) "+" else "-"}")
541+
MG4Hardware.mediaVolumeStep(delta)
542+
}
543+
537544
ShortcutAction.MEDIA_NEXT, ShortcutAction.MEDIA_PREVIOUS,
538545
ShortcutAction.MEDIA_PLAY_PAUSE -> {
539546
// Aucune lecture préalable : contrairement aux autres actions de ce bloc, il n'y

‎app/src/main/java/com/mg4/control/shortcut/ShortcutAction.kt‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ enum class ShortcutAction(val id: Int) {
4444
// envoient une touche au système, qui la remet à l'application en train de jouer.
4545
MEDIA_NEXT(31),
4646
MEDIA_PREVIOUS(32),
47-
MEDIA_PLAY_PAUSE(33);
47+
MEDIA_PLAY_PAUSE(33),
48+
49+
// Volume : réglage du VÉHICULE, contrairement aux trois précédentes. Il ne dépend d'aucune
50+
// application et fonctionne donc même quand les touches média restent sans effet.
51+
VOLUME_UP(34),
52+
VOLUME_DOWN(35);
4853

4954
companion object {
5055
fun fromId(id: Int) = values().firstOrNull { it.id == id } ?: NONE

‎app/src/main/java/com/mg4/control/ui/SettingsFragment.kt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,9 @@ class SettingsFragment : Fragment() {
508508
MG4Hardware.runSpeedDiag()
509509
// Sonde climatisation : lecture seule, repère ce qui répond avant tout pilotage.
510510
MG4Hardware.runClimateDiag()
511+
// Sonde média : qui joue, et surtout quelles sessions média existent — c'est ce qui
512+
// décide si une touche « piste suivante » peut aboutir quelque part.
513+
MG4Hardware.runMediaDiag()
511514
// Sonde consommation de données : lecture seule, aucune API véhicule impliquée.
512515
DataUsageProbe.run(ctx)
513516
// Sonde somnolence / sensibilité / ESC : lecture seule (elle ne bascule RIEN — un

‎app/src/main/java/com/mg4/control/ui/ShortcutsFragment.kt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ class ShortcutsFragment : Fragment() {
140140
add(ActionItem(getString(R.string.shortcuts_action_media_next), ShortcutAction.MEDIA_NEXT))
141141
add(ActionItem(getString(R.string.shortcuts_action_media_prev), ShortcutAction.MEDIA_PREVIOUS))
142142
add(ActionItem(getString(R.string.shortcuts_action_media_play_pause), ShortcutAction.MEDIA_PLAY_PAUSE))
143+
// Volume : pas de filtre non plus — la voie SAIC est tentée d'abord, AudioManager
144+
// prend le relais ailleurs, donc il y a toujours un chemin.
145+
add(ActionItem(getString(R.string.shortcuts_action_volume_up), ShortcutAction.VOLUME_UP))
146+
add(ActionItem(getString(R.string.shortcuts_action_volume_down), ShortcutAction.VOLUME_DOWN))
143147
add(ActionItem(getString(R.string.shortcuts_action_apply_profile), ShortcutAction.APPLY_PROFILE))
144148
add(ActionItem(getString(R.string.shortcuts_action_profile_picker), ShortcutAction.PROFILE_PICKER))
145149
add(ActionItem(getString(R.string.shortcuts_action_open_app), ShortcutAction.OPEN_APP))

‎app/src/main/res/values-de/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,8 @@
468468
<string name="shortcuts_action_media_next">Nächster Titel</string>
469469
<string name="shortcuts_action_media_prev">Vorheriger Titel</string>
470470
<string name="shortcuts_action_media_play_pause">Wiedergabe / Pause</string>
471+
472+
<!-- Raccourcis : volume -->
473+
<string name="shortcuts_action_volume_up">Lautstärke +</string>
474+
<string name="shortcuts_action_volume_down">Lautstärke -</string>
471475
</resources>

‎app/src/main/res/values-en/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,8 @@
468468
<string name="shortcuts_action_media_next">Next track</string>
469469
<string name="shortcuts_action_media_prev">Previous track</string>
470470
<string name="shortcuts_action_media_play_pause">Play / Pause</string>
471+
472+
<!-- Raccourcis : volume -->
473+
<string name="shortcuts_action_volume_up">Volume +</string>
474+
<string name="shortcuts_action_volume_down">Volume -</string>
471475
</resources>

‎app/src/main/res/values-es/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,8 @@
468468
<string name="shortcuts_action_media_next">Pista siguiente</string>
469469
<string name="shortcuts_action_media_prev">Pista anterior</string>
470470
<string name="shortcuts_action_media_play_pause">Reproducir / Pausa</string>
471+
472+
<!-- Raccourcis : volume -->
473+
<string name="shortcuts_action_volume_up">Volumen +</string>
474+
<string name="shortcuts_action_volume_down">Volumen -</string>
471475
</resources>

‎app/src/main/res/values-it/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,8 @@
468468
<string name="shortcuts_action_media_next">Traccia successiva</string>
469469
<string name="shortcuts_action_media_prev">Traccia precedente</string>
470470
<string name="shortcuts_action_media_play_pause">Riproduci / Pausa</string>
471+
472+
<!-- Raccourcis : volume -->
473+
<string name="shortcuts_action_volume_up">Volume +</string>
474+
<string name="shortcuts_action_volume_down">Volume -</string>
471475
</resources>

‎app/src/main/res/values-pt/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,8 @@
468468
<string name="shortcuts_action_media_next">Faixa seguinte</string>
469469
<string name="shortcuts_action_media_prev">Faixa anterior</string>
470470
<string name="shortcuts_action_media_play_pause">Reproduzir / Pausa</string>
471+
472+
<!-- Raccourcis : volume -->
473+
<string name="shortcuts_action_volume_up">Volume +</string>
474+
<string name="shortcuts_action_volume_down">Volume -</string>
471475
</resources>

0 commit comments

Comments
 (0)