@@ -3907,6 +3907,43 @@ object MG4Hardware {
39073907 }
39083908 }
39093909
3910+ /* *
3911+ * CarPlay / Android Auto joue-t-il ? `null` si on ne peut pas conclure.
3912+ *
3913+ * `getLastCpAaAudioInfoBean` (tx 0x7) rend un `AudioInfoBean` dont le champ `mPlayState`
3914+ * vaut 3 en lecture — la carte média du launcher le compare à cette valeur exacte. Il faut
3915+ * dérouler le bean dans l'ordre de son `writeToParcel` : id(long), durée(long), puis sept
3916+ * chaînes, deux longs, une chaîne, et enfin **l'état(int)**.
3917+ *
3918+ * Sans cette lecture, la projection retombait sur `isMusicActive`, qui reste vrai deux à
3919+ * trois secondes après une pause : le raccourci renvoyait une pause au lieu d'une reprise,
3920+ * et il fallait patienter avant que la bascule redevienne possible.
3921+ */
3922+ private fun cpAaEnLecture (): Boolean? {
3923+ val binder = serviceBinder(ACT_CPAA , MEDIA_PKG , MEDIA_CLS ) ? : return null
3924+ val data = Parcel .obtain()
3925+ val reply = Parcel .obtain()
3926+ return try {
3927+ data.writeInterfaceToken(DESC_CPAA )
3928+ binder.transact(0x7 , data, reply, 0 )
3929+ reply.readException()
3930+ if (reply.readInt() == 0 ) return null // bean nul : rien à conclure
3931+ reply.readLong(); reply.readLong() // id, durée
3932+ repeat(7 ) { reply.readString() } // nom, pochette, chemin, artiste, utilisateur, avatar, album
3933+ reply.readLong(); reply.readLong() // ajout, dernière lecture
3934+ reply.readString() // position lisible
3935+ val etat = reply.readInt()
3936+ AppLogger .i(MEDIA_TAG , " état projection = $etat ($PLAYER_STATUS_START = en lecture)" )
3937+ etat == PLAYER_STATUS_START
3938+ } catch (e: Exception ) {
3939+ AppLogger .w(MEDIA_TAG , " état projection illisible : ${(e.cause ? : e).message} " )
3940+ null
3941+ } finally {
3942+ data.recycle()
3943+ reply.recycle()
3944+ }
3945+ }
3946+
39103947 /* * Source audio réellement active, ou -1 si le service SAIC ne répond pas. */
39113948 private fun mediaSourceCourante (): Int {
39123949 val v = mediaLireInt(ACT_STATUS , DESC_STATUS , 0x9 ) ? : return - 1 // getCurrentMediaSource
@@ -3928,6 +3965,8 @@ object MG4Hardware {
39283965 SRC_BT -> mediaLireInt(ACT_BT , DESC_BT , 0x9 )?.let { it != 0 }
39293966 // getPlayerStatus : un état parmi PLAYER_STATUS_*.
39303967 SRC_ONLINE -> mediaLireInt(ACT_ONLINE , DESC_ONLINE , 0x6 )?.let { it == PLAYER_STATUS_START }
3968+ // La projection expose son état dans son bean, pas par un getter direct.
3969+ SRC_CARPLAY , SRC_AA -> cpAaEnLecture()
39313970 else -> null
39323971 }
39333972 if (reel != null ) {
@@ -4036,8 +4075,6 @@ object MG4Hardware {
40364075 cible == SRC_CARPLAY || cible == SRC_AA -> mediaTransact(ACT_CPAA , DESC_CPAA , when (cmd) {
40374076 CmdMedia .SUIVANT -> 4
40384077 CmdMedia .PRECEDENT -> 3
4039- // La projection n'expose pas son état : isMusicActive est le seul indice, et il
4040- // suffit ici — il retombe à faux quand la lecture s'arrête vraiment.
40414078 CmdMedia .LECTURE_PAUSE -> if (enLecture(cible)) 2 else 1
40424079 })
40434080
0 commit comments