Add an action to pause the emulator process

This commit is contained in:
Abandoned Cart 2023-02-15 12:24:38 -05:00 committed by Billy Laws
parent a1143ee5de
commit 95a679e5cd
3 changed files with 55 additions and 25 deletions

View File

@ -91,9 +91,10 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
*/ */
private var desiredRefreshRate = 60f private var desiredRefreshRate = 60f
private val muteIntentAction = "$packageName.EMULATOR_MUTE"
private lateinit var pictureInPictureParamsBuilder : PictureInPictureParams.Builder private lateinit var pictureInPictureParamsBuilder : PictureInPictureParams.Builder
private lateinit var muteReceiver : BroadcastReceiver private val pauseIntentAction = "$packageName.EMULATOR_PAUSE"
private val muteIntentAction = "$packageName.EMULATOR_MUTE"
private lateinit var pictureInPictureReceiver : BroadcastReceiver
@Inject @Inject
lateinit var appSettings : AppSettings lateinit var appSettings : AppSettings
@ -105,6 +106,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
lateinit var inputHandler : InputHandler lateinit var inputHandler : InputHandler
private var gameSurface : Surface? = null
/** /**
* This is the entry point into the emulation code for libskyline * This is the entry point into the emulation code for libskyline
* *
@ -274,12 +277,22 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
pictureInPictureParamsBuilder = PictureInPictureParams.Builder() pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
val pictureInPictureActions : MutableList<RemoteAction> = mutableListOf()
val pendingFlags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
val pauseIcon = Icon.createWithResource(this, R.drawable.ic_pause)
val pausePendingIntent = PendingIntent.getBroadcast(this, R.drawable.ic_pause, Intent(pauseIntentAction), pendingFlags)
val pauseRemoteAction = RemoteAction(pauseIcon, getString(R.string.pause), getString(R.string.pause_emulator), pausePendingIntent)
pictureInPictureActions.add(pauseRemoteAction)
if (!emulationSettings.isAudioOutputDisabled) { if (!emulationSettings.isAudioOutputDisabled) {
val muteIcon = Icon.createWithResource(this, R.drawable.ic_volume_mute) val muteIcon = Icon.createWithResource(this, R.drawable.ic_volume_mute)
val mutePendingIntent = PendingIntent.getBroadcast(this, R.drawable.ic_volume_mute, Intent(muteIntentAction), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) val mutePendingIntent = PendingIntent.getBroadcast(this, R.drawable.ic_volume_mute, Intent(muteIntentAction), pendingFlags)
val muteRemoteAction = RemoteAction(muteIcon, getString(R.string.mute), getString(R.string.disable_audio_output), mutePendingIntent) val muteRemoteAction = RemoteAction(muteIcon, getString(R.string.mute), getString(R.string.disable_audio_output), mutePendingIntent)
pictureInPictureParamsBuilder.setActions(mutableListOf(muteRemoteAction)) pictureInPictureActions.add(muteRemoteAction)
} }
pictureInPictureParamsBuilder.setActions(pictureInPictureActions)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
pictureInPictureParamsBuilder.setAutoEnterEnabled(true) pictureInPictureParamsBuilder.setAutoEnterEnabled(true)
@ -371,32 +384,37 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) { override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig) super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
if (isInPictureInPictureMode) { if (isInPictureInPictureMode) {
if (!emulationSettings.isAudioOutputDisabled) { pictureInPictureReceiver = object : BroadcastReceiver() {
muteReceiver = object : BroadcastReceiver() {
override fun onReceive(context : Context?, intent : Intent) { override fun onReceive(context : Context?, intent : Intent) {
if (intent.action == muteIntentAction) if (intent.action == pauseIntentAction)
setSurface(null)
else if (intent.action == muteIntentAction)
changeAudioStatus(false) changeAudioStatus(false)
} }
} }
IntentFilter(muteIntentAction).also { IntentFilter().apply {
registerReceiver(muteReceiver, it) addAction(pauseIntentAction)
} if (!emulationSettings.isAudioOutputDisabled)
addAction(muteIntentAction)
}.also {
registerReceiver(pictureInPictureReceiver, it)
} }
binding.onScreenControllerView.isGone = true binding.onScreenControllerView.isGone = true
binding.onScreenControllerToggle.isGone = true binding.onScreenControllerToggle.isGone = true
} else { } else {
if (!emulationSettings.isAudioOutputDisabled) {
changeAudioStatus(true)
try { try {
if (this::muteReceiver.isInitialized) if (this::pictureInPictureReceiver.isInitialized)
unregisterReceiver(muteReceiver) unregisterReceiver(pictureInPictureReceiver)
} catch (ignored : Exception) { } catch (ignored : Exception) {
// Perfectly acceptable and should be ignored // Perfectly acceptable and should be ignored
} }
}
setSurface(gameSurface)
if (!emulationSettings.isAudioOutputDisabled)
changeAudioStatus(true)
binding.onScreenControllerView.apply { binding.onScreenControllerView.apply {
controllerType = inputHandler.getFirstControllerType() controllerType = inputHandler.getFirstControllerType()
@ -447,9 +465,11 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
holder.surface.setFrameRate(desiredRefreshRate, if (emulationSettings.maxRefreshRate) Surface.FRAME_RATE_COMPATIBILITY_DEFAULT else Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) holder.surface.setFrameRate(desiredRefreshRate, if (emulationSettings.maxRefreshRate) Surface.FRAME_RATE_COMPATIBILITY_DEFAULT else Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE)
while (emulationThread!!.isAlive) while (emulationThread!!.isAlive)
if (setSurface(holder.surface)) if (setSurface(holder.surface)) {
gameSurface = holder.surface
return return
} }
}
/** /**
* This is purely used for debugging surface changes * This is purely used for debugging surface changes
@ -464,9 +484,11 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
override fun surfaceDestroyed(holder : SurfaceHolder) { override fun surfaceDestroyed(holder : SurfaceHolder) {
Log.d(Tag, "surfaceDestroyed Holder: $holder") Log.d(Tag, "surfaceDestroyed Holder: $holder")
while (emulationThread!!.isAlive) while (emulationThread!!.isAlive)
if (setSurface(null)) if (setSurface(null)) {
gameSurface = null
return return
} }
}
override fun dispatchKeyEvent(event : KeyEvent) : Boolean { override fun dispatchKeyEvent(event : KeyEvent) : Boolean {
return if (inputHandler.handleKeyEvent(event)) true else super.dispatchKeyEvent(event) return if (inputHandler.handleKeyEvent(event)) true else super.dispatchKeyEvent(event)

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>

View File

@ -23,6 +23,10 @@
<string name="invalid_file">Invalid file</string> <string name="invalid_file">Invalid file</string>
<string name="missing_title_key">Missing title key</string> <string name="missing_title_key">Missing title key</string>
<string name="incomplete_prod_keys">Incomplete production keys</string> <string name="incomplete_prod_keys">Incomplete production keys</string>
<!-- Picture-In-Picture -->
<string name="pause">Pause</string>
<string name="pause_emulator">Pause emulator process</string>
<string name="mute">Mute</string>
<!-- Settings - Content --> <!-- Settings - Content -->
<string name="content">Content</string> <string name="content">Content</string>
<string name="open_data_directory">View Internal Directory</string> <string name="open_data_directory">View Internal Directory</string>
@ -87,7 +91,6 @@
<string name="respect_display_cutout_disabled">Allow UI elements to be drawn in the cutout area</string> <string name="respect_display_cutout_disabled">Allow UI elements to be drawn in the cutout area</string>
<!-- Settings - Audio --> <!-- Settings - Audio -->
<string name="audio">Audio</string> <string name="audio">Audio</string>
<string name="mute">Mute</string>
<string name="disable_audio_output">Disable Audio Output</string> <string name="disable_audio_output">Disable Audio Output</string>
<string name="disable_audio_output_enabled">Audio output is disabled</string> <string name="disable_audio_output_enabled">Audio output is disabled</string>
<string name="disable_audio_output_disabled">Audio output is enabled</string> <string name="disable_audio_output_disabled">Audio output is enabled</string>