android: Remove LocalBroadcastManager

This causes a couple of minor changes to directory initialization. We don't have a lengthy initialization step so we could spend less time creating state receivers and just run initialization on the main thread. We also don't have a situation where external storage will be a concern so checks are removed in favor of a binary check to see if initialization is ready.

This additionally removes the unused DoFrame callback.
This commit is contained in:
Charles Lombardo 2023-04-04 04:03:55 -04:00 committed by bunnei
parent 9d7a60346f
commit a827486391
11 changed files with 17 additions and 225 deletions

View File

@ -142,7 +142,6 @@ dependencies {
implementation 'androidx.window:window:1.0.0'
implementation 'org.ini4j:ini4j:0.5.4'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
}

View File

@ -218,8 +218,6 @@ public final class NativeLibrary {
public static native void SurfaceDestroyed();
public static native void DoFrame();
/**
* Unpauses emulation from a paused state.
*/

View File

@ -5,31 +5,25 @@ package org.yuzu.yuzu_emu.features.settings.ui
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.view.Menu
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
import org.yuzu.yuzu_emu.utils.*
class SettingsActivity : AppCompatActivity(), SettingsActivityView {
private val presenter = SettingsActivityPresenter(this)
private var dialog: AlertDialog? = null
private lateinit var binding: ActivitySettingsBinding
@ -134,47 +128,6 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
return duration != 0f && transition != 0f
}
override fun startDirectoryInitializationService(
receiver: DirectoryStateReceiver?,
filter: IntentFilter
) {
LocalBroadcastManager.getInstance(this).registerReceiver(
receiver!!,
filter
)
DirectoryInitialization.start(this)
}
override fun stopListeningToDirectoryInitializationService(receiver: DirectoryStateReceiver) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
}
override fun showLoading() {
if (dialog == null) {
val loadingBinding = DialogProgressBarBinding.inflate(layoutInflater)
loadingBinding.progressBar.isIndeterminate = true
dialog = MaterialAlertDialogBuilder(this)
.setTitle(R.string.load_settings)
.setView(loadingBinding.root)
.setCancelable(false)
.create()
}
dialog!!.show()
}
override fun hideLoading() {
dialog!!.dismiss()
}
override fun showExternalStorageNotMountedHint() {
Toast.makeText(
this,
R.string.external_storage_not_mounted,
Toast.LENGTH_SHORT
).show()
}
override fun onSettingsFileLoaded() {
val fragment: SettingsFragmentView? = settingsFragment
fragment?.loadSettingsList()

View File

@ -3,15 +3,13 @@
package org.yuzu.yuzu_emu.features.settings.ui
import android.content.IntentFilter
import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState
import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver
import org.yuzu.yuzu_emu.utils.Log
import java.io.File
@ -19,7 +17,6 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
val settings: Settings get() = activityView.settings
private var shouldSave = false
private var directoryStateReceiver: DirectoryStateReceiver? = null
private lateinit var menuTag: String
private lateinit var gameId: String
@ -54,33 +51,14 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
Log.error(DirectoryInitialization.userDirectory + "/config/" + SettingsFile.FILE_NAME_CONFIG + ".ini")
Log.error("yuzu config file could not be found!")
}
if (DirectoryInitialization.areDirectoriesReady()) {
loadSettingsUI()
} else {
activityView.showLoading()
val statusIntentFilter = IntentFilter(DirectoryInitialization.BROADCAST_ACTION)
directoryStateReceiver =
DirectoryStateReceiver { directoryInitializationState: DirectoryInitializationState ->
if (directoryInitializationState == DirectoryInitializationState.YUZU_DIRECTORIES_INITIALIZED) {
activityView.hideLoading()
loadSettingsUI()
} else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE) {
activityView.showExternalStorageNotMountedHint()
activityView.hideLoading()
}
}
activityView.startDirectoryInitializationService(
directoryStateReceiver,
statusIntentFilter
)
if (!DirectoryInitialization.areDirectoriesReady) {
DirectoryInitialization.start(activityView as Context)
}
loadSettingsUI()
}
fun onStop(finishing: Boolean) {
if (directoryStateReceiver != null) {
activityView.stopListeningToDirectoryInitializationService(directoryStateReceiver!!)
directoryStateReceiver = null
}
if (finishing && shouldSave) {
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...")
settings.saveSettings(activityView)

View File

@ -3,9 +3,7 @@
package org.yuzu.yuzu_emu.features.settings.ui
import android.content.IntentFilter
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver
/**
* Abstraction for the Activity that manages SettingsFragments.
@ -56,37 +54,4 @@ interface SettingsActivityView {
* unless this has been called, the Activity will not save to disk.
*/
fun onSettingChanged()
/**
* Show loading dialog while loading the settings
*/
fun showLoading()
/**
* Hide the loading the dialog
*/
fun hideLoading()
/**
* Show a hint to the user that the app needs the external storage to be mounted
*/
fun showExternalStorageNotMountedHint()
/**
* Start the DirectoryInitialization and listen for the result.
*
* @param receiver the broadcast receiver for the DirectoryInitialization
* @param filter the Intent broadcasts to be received.
*/
fun startDirectoryInitializationService(
receiver: DirectoryStateReceiver?,
filter: IntentFilter
)
/**
* Stop listening to the DirectoryInitialization.
*
* @param receiver The broadcast receiver to unregister.
*/
fun stopListeningToDirectoryInitializationService(receiver: DirectoryStateReceiver)
}

View File

@ -4,14 +4,13 @@
package org.yuzu.yuzu_emu.fragments
import android.content.Context
import android.content.IntentFilter
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.*
import android.widget.TextView
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.widget.PopupMenu
import androidx.core.content.res.ResourcesCompat
@ -19,7 +18,6 @@ import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.NativeLibrary
@ -32,13 +30,11 @@ import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState
import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable
class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.FrameCallback {
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private lateinit var preferences: SharedPreferences
private lateinit var emulationState: EmulationState
private var directoryStateReceiver: DirectoryStateReceiver? = null
private var emulationActivity: EmulationActivity? = null
private var perfStatsUpdater: (() -> Unit)? = null
@ -144,25 +140,16 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
override fun onResume() {
super.onResume()
Choreographer.getInstance().postFrameCallback(this)
if (DirectoryInitialization.areDirectoriesReady()) {
emulationState.run(emulationActivity!!.isActivityRecreated)
} else {
setupDirectoriesThenStartEmulation()
if (!DirectoryInitialization.areDirectoriesReady) {
DirectoryInitialization.start(requireContext())
}
emulationState.run(emulationActivity!!.isActivityRecreated)
}
override fun onPause() {
if (directoryStateReceiver != null) {
LocalBroadcastManager.getInstance(requireActivity()).unregisterReceiver(
directoryStateReceiver!!
)
directoryStateReceiver = null
}
if (emulationState.isRunning) {
emulationState.pause()
}
Choreographer.getInstance().removeFrameCallback(this)
super.onPause()
}
@ -176,36 +163,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
super.onDetach()
}
private fun setupDirectoriesThenStartEmulation() {
val statusIntentFilter = IntentFilter(
DirectoryInitialization.BROADCAST_ACTION
)
directoryStateReceiver =
DirectoryStateReceiver { directoryInitializationState: DirectoryInitializationState ->
if (directoryInitializationState ==
DirectoryInitializationState.YUZU_DIRECTORIES_INITIALIZED
) {
emulationState.run(emulationActivity!!.isActivityRecreated)
} else if (directoryInitializationState ==
DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE
) {
Toast.makeText(
context,
R.string.external_storage_not_mounted,
Toast.LENGTH_SHORT
)
.show()
}
}
// Registers the DirectoryStateReceiver and its intent filters
LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(
directoryStateReceiver!!,
statusIntentFilter
)
DirectoryInitialization.start(requireContext())
}
fun refreshInputOverlay() {
binding.surfaceInputOverlay.refreshControls()
}
@ -259,11 +216,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
emulationState.clearSurface()
}
override fun doFrame(frameTimeNanos: Long) {
Choreographer.getInstance().postFrameCallback(this)
NativeLibrary.DoFrame()
}
private fun showOverlayOptions() {
val anchor = binding.inGameMenu.findViewById<View>(R.id.menu_overlay_controls)
val popup = PopupMenu(requireContext(), anchor)
@ -474,7 +426,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
}
companion object {
private val perfStatsUpdateHandler = Handler()
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
fun newInstance(game: Game): EmulationFragment {
val args = Bundle()

View File

@ -41,7 +41,7 @@ class MainActivity : AppCompatActivity(), MainView {
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady() }
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
ThemeHelper.setTheme(this)

View File

@ -4,46 +4,26 @@
package org.yuzu.yuzu_emu.utils
import android.content.Context
import android.content.Intent
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import org.yuzu.yuzu_emu.NativeLibrary
import java.io.IOException
import java.util.concurrent.atomic.AtomicBoolean
object DirectoryInitialization {
const val BROADCAST_ACTION = "org.yuzu.yuzu_emu.BROADCAST"
const val EXTRA_STATE = "directoryState"
@Volatile
private var directoryState: DirectoryInitializationState? = null
private var userPath: String? = null
private val isDirectoryInitializationRunning = AtomicBoolean(false)
var areDirectoriesReady: Boolean = false
@JvmStatic
fun start(context: Context) {
// Can take a few seconds to run, so don't block UI thread.
Runnable { init(context) }.run()
}
private fun init(context: Context) {
if (!isDirectoryInitializationRunning.compareAndSet(false, true)) return
if (directoryState != DirectoryInitializationState.YUZU_DIRECTORIES_INITIALIZED) {
if (!areDirectoriesReady) {
initializeInternalStorage(context)
NativeLibrary.InitializeEmulation()
directoryState = DirectoryInitializationState.YUZU_DIRECTORIES_INITIALIZED
areDirectoriesReady = true
}
isDirectoryInitializationRunning.set(false)
sendBroadcastState(directoryState, context)
}
fun areDirectoriesReady(): Boolean {
return directoryState == DirectoryInitializationState.YUZU_DIRECTORIES_INITIALIZED
}
val userDirectory: String?
get() {
checkNotNull(directoryState) { "DirectoryInitialization has to run at least once!" }
check(!isDirectoryInitializationRunning.get()) { "DirectoryInitialization has to finish running first!" }
check(areDirectoriesReady) { "Directory initialization is not ready!" }
return userPath
}
@ -55,15 +35,4 @@ object DirectoryInitialization {
e.printStackTrace()
}
}
private fun sendBroadcastState(state: DirectoryInitializationState?, context: Context) {
val localIntent = Intent(BROADCAST_ACTION)
.putExtra(EXTRA_STATE, state)
LocalBroadcastManager.getInstance(context).sendBroadcast(localIntent)
}
enum class DirectoryInitializationState {
YUZU_DIRECTORIES_INITIALIZED,
CANT_FIND_EXTERNAL_STORAGE
}
}

View File

@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState
class DirectoryStateReceiver(var callback: (DirectoryInitializationState) -> Unit) :
BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val state = intent
.getSerializableExtra(DirectoryInitialization.EXTRA_STATE) as DirectoryInitializationState
callback.invoke(state)
}
}

View File

@ -367,8 +367,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
EmulationSession::GetInstance().SurfaceChanged();
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused]] jclass clazz) {}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env,
[[maybe_unused]] jclass clazz,
jint layout_option,

View File

@ -98,8 +98,6 @@
<string name="load_settings">Loading Settings…</string>
<string name="external_storage_not_mounted">The external storage needs to be available in order to use yuzu</string>
<string name="empty_gamelist">No files were found or no game directory has been selected yet.</string>
<!-- Software keyboard -->