Skip to content

Commit 79f4fea

Browse files
committed
#1971 fix: media actions work again in some apps, like YouTube
1 parent 03cb80c commit 79f4fea

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- #1986 trigger screen is usable on slightly rectangular screens with a low DPI.
1414
- #1972 Expert Mode works on Android 10.
1515
- #1976 Panic in Rust system bridge code on some devices.
16+
- #1971 Media actions work again in some apps, like YouTube.
1617
- Bugs with expert mode auto starting time.
1718

1819
## [4.0.0 Beta 6](https://github.com/sds100/KeyMapper/releases/tag/v4.0.0-beta.06)

system/src/main/java/io/github/sds100/keymapper/system/media/AndroidMediaAdapter.kt

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import android.media.MediaPlayer
99
import android.media.session.MediaController
1010
import android.media.session.MediaSessionManager
1111
import android.media.session.PlaybackState
12+
import android.view.KeyEvent
1213
import androidx.core.content.getSystemService
1314
import androidx.core.net.toUri
1415
import dagger.hilt.android.qualifiers.ApplicationContext
@@ -87,7 +88,7 @@ class AndroidMediaAdapter @Inject constructor(
8788
session.transportControls.fastForward()
8889
return Success(Unit)
8990
} else {
90-
return KMError.MediaActionUnsupported
91+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, packageName)
9192
}
9293
}
9394

@@ -98,7 +99,7 @@ class AndroidMediaAdapter @Inject constructor(
9899
session.transportControls.rewind()
99100
return Success(Unit)
100101
} else {
101-
return KMError.MediaActionUnsupported
102+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_REWIND, packageName)
102103
}
103104
}
104105

@@ -109,7 +110,7 @@ class AndroidMediaAdapter @Inject constructor(
109110
session.transportControls.play()
110111
return Success(Unit)
111112
} else {
112-
return KMError.MediaActionUnsupported
113+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY, packageName)
113114
}
114115
}
115116

@@ -120,7 +121,7 @@ class AndroidMediaAdapter @Inject constructor(
120121
session.transportControls.pause()
121122
return Success(Unit)
122123
} else {
123-
return KMError.MediaActionUnsupported
124+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PAUSE, packageName)
124125
}
125126
}
126127

@@ -135,7 +136,7 @@ class AndroidMediaAdapter @Inject constructor(
135136
}
136137
return Success(Unit)
137138
} else {
138-
return KMError.MediaActionUnsupported
139+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, packageName)
139140
}
140141
}
141142

@@ -146,7 +147,7 @@ class AndroidMediaAdapter @Inject constructor(
146147
session.transportControls.skipToPrevious()
147148
return Success(Unit)
148149
} else {
149-
return KMError.MediaActionUnsupported
150+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS, packageName)
150151
}
151152
}
152153

@@ -157,7 +158,7 @@ class AndroidMediaAdapter @Inject constructor(
157158
session.transportControls.skipToNext()
158159
return Success(Unit)
159160
} else {
160-
return KMError.MediaActionUnsupported
161+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_NEXT, packageName)
161162
}
162163
}
163164

@@ -168,7 +169,7 @@ class AndroidMediaAdapter @Inject constructor(
168169
session.transportControls.stop()
169170
return Success(Unit)
170171
} else {
171-
return KMError.MediaActionUnsupported
172+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_STOP, packageName)
172173
}
173174
}
174175

@@ -180,7 +181,7 @@ class AndroidMediaAdapter @Inject constructor(
180181
session.transportControls.seekTo(position + SEEK_AMOUNT)
181182
return Success(Unit)
182183
} else {
183-
return KMError.MediaActionUnsupported
184+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_STEP_FORWARD, packageName)
184185
}
185186
}
186187

@@ -192,7 +193,7 @@ class AndroidMediaAdapter @Inject constructor(
192193
session.transportControls.seekTo(max(0, position - SEEK_AMOUNT))
193194
return Success(Unit)
194195
} else {
195-
return KMError.MediaActionUnsupported
196+
return sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_STEP_BACKWARD, packageName)
196197
}
197198
}
198199

@@ -277,6 +278,21 @@ class AndroidMediaAdapter @Inject constructor(
277278
activeMediaSessions.update { mediaSessions }
278279
}
279280

281+
// Important! See issue #1971. Some apps do not expose media controls or say they support
282+
// media control actions but they still respond to key events.
283+
private fun sendMediaKeyEvent(keyCode: Int, packageName: String?): KMResult<*> {
284+
if (packageName == null) {
285+
audioManager.dispatchMediaKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, keyCode))
286+
audioManager.dispatchMediaKeyEvent(KeyEvent(KeyEvent.ACTION_UP, keyCode))
287+
} else {
288+
val session = getPackageMediaSession(packageName) ?: return KMError.NoMediaSessions
289+
session.dispatchMediaButtonEvent(KeyEvent(KeyEvent.ACTION_DOWN, keyCode))
290+
session.dispatchMediaButtonEvent(KeyEvent(KeyEvent.ACTION_UP, keyCode))
291+
}
292+
293+
return Success(Unit)
294+
}
295+
280296
private fun MediaController.isPlaybackActionSupported(action: Long): Boolean =
281297
(playbackState?.actions ?: 0) and action != 0L
282298

0 commit comments

Comments
 (0)