Compare commits

..

58 Commits

Author SHA1 Message Date
e1ea5ba66b Android 255 2024-02-18 20:17:36 +00:00
9b29d2c340 Merge yuzu-emu#13070 2024-02-18 20:17:35 +00:00
f688e8cc5d Merge yuzu-emu#13048 2024-02-18 20:17:35 +00:00
f5322ea1ee Merge yuzu-emu#13035 2024-02-18 20:17:35 +00:00
5c92adbcf6 Merge yuzu-emu#13030 2024-02-18 20:17:35 +00:00
b66fd41ba1 Merge yuzu-emu#13026 2024-02-18 20:17:35 +00:00
2938aa58ed Merge yuzu-emu#13006 2024-02-18 20:17:35 +00:00
78379761cc Merge yuzu-emu#13000 2024-02-18 20:17:35 +00:00
8614751812 Merge yuzu-emu#12749 2024-02-18 20:17:35 +00:00
a224414f0f Merge yuzu-emu#12461 2024-02-18 20:17:35 +00:00
baf65362ab Merge yuzu-emu#10529 2024-02-18 20:17:35 +00:00
5361027ef0 Merge pull request #13068 from german77/no_errors
core: hid: Remove driver errors from log
2024-02-18 13:30:54 -05:00
56721517ea core: hid: Remove driver errors from log 2024-02-18 10:54:56 -06:00
da225d4aa1 Merge pull request #13067 from t895/xbox-automap-invert
android: Flip AB/XY for xbox controllers during auto-mapping
2024-02-18 10:48:54 -05:00
8d74c107f5 android: Flip AB/XY for xbox controllers during auto-mapping 2024-02-18 10:40:33 -05:00
1fc86b1e3a Merge pull request #13032 from german77/qlauncher
service: Implement functions needed by Qlaunch
2024-02-18 10:37:52 -05:00
5583957616 Merge pull request #13064 from t895/auto-map-fail
android: Only do first startup automapping if nothing has been mapped
2024-02-18 10:27:49 -05:00
6d731e1aa1 Merge pull request #13049 from Leystryku/master
Fix Just Dance 2023 not booting
2024-02-18 10:25:18 -05:00
839ded7d59 Merge pull request #13065 from t895/cancel-button-fail
android: Show cancel button for the content install notice
2024-02-18 10:25:04 -05:00
f57281ebc1 Merge pull request #13066 from t895/touch-fix
android: Map touches to touchscreen
2024-02-18 10:24:58 -05:00
0a3bc6c0cf android: Map touches to touchscreen
I neglected to map touches to the touchscreen when refactoring in the input mapping PR. This fixes that regression.
2024-02-18 10:00:37 -05:00
55a7815064 android: Show cancel button for the content install notice 2024-02-18 09:23:46 -05:00
a1c4f53c8c android: Only do first startup automapping if nothing has been mapped 2024-02-18 09:18:54 -05:00
8bbb44a74e service: Change unique_ptr to make_unique in GetCacheStorageMax 2024-02-18 07:03:50 +01:00
bc5ae04ea0 file_sys: Formatting changes and use unique_ptr in GetCacheStorageMax 2024-02-18 06:17:35 +01:00
4f387b0b74 file_sys: Fix nacp field cache_storage_max_index datatype 2024-02-18 06:00:42 +01:00
bdf8aca750 Merge pull request #13047 from anpilley/import-firmware
Import firmware from folder of loose NCA files
2024-02-17 23:18:00 -05:00
acfc4d6dfb Merge pull request #13054 from t895/lifecycle-utils
android: Create lifecycle utility to simplify common StateFlow operations
2024-02-17 23:17:49 -05:00
35a3c7226a android: Create lifecycle utility to simplify common StateFlow operations 2024-02-17 23:09:09 -05:00
d93fdc8a6c service: Add proper GetCacheStorageMax implementation to IApplicationFunctions 2024-02-18 05:02:35 +01:00
5d3c7433b8 Merge pull request #13050 from t895/marquee-helper
android: Use extension functions for view visibility and text marquee
2024-02-17 22:48:36 -05:00
0010d42f82 android: Use extension functions for view visibility and text marquee 2024-02-17 22:45:33 -05:00
316089c39f Merge pull request #13052 from t895/serializable-stuff
android: Move CoreErrorDialogFragment to its own file
2024-02-17 22:22:46 -05:00
5024df1925 Merge pull request #13051 from german77/cheatmiss
dmnt: cheats: Fix valid address range
2024-02-17 22:22:14 -05:00
e7146309de Merge pull request #13034 from t895/map-all-the-inputs
android: Input mapping
2024-02-17 22:22:06 -05:00
c327d2a62c android: Move CoreErrorDialogFragment to its own file 2024-02-17 21:58:25 -05:00
cb2e312f13 Add check for corrupted firmware files after install. 2024-02-18 12:31:14 +11:00
366bb52ec8 dmnt: cheats: Fix valid address range 2024-02-17 19:10:17 -06:00
82949085c0 fsp: Add FlushAccessLogOnSdCard stub 2024-02-18 00:52:22 +01:00
90c43aa2e7 service: Add GetCacheStorageMax stub to IApplicationFunctions 2024-02-18 00:49:41 +01:00
53f8383354 Merge pull request #13017 from liamwhite/suspension
kernel: add and enable system suspend type
2024-02-17 17:00:07 -06:00
36108ce2be Merge pull request #13040 from Kelebek1/timezone_shutdown
Close reference to TimeZoneBinary on game close
2024-02-17 17:53:53 -05:00
e31c926bf0 >.> spelling 2024-02-18 07:58:41 +11:00
59ede32f8e cleanup by clang-format. 2024-02-18 07:41:24 +11:00
9eba64adce Improve behavior when one or more firmware files can't be deleted. 2024-02-18 07:38:47 +11:00
50ecad547e android: Input mapping 2024-02-17 12:32:33 -05:00
34fb14ec9a Close reference to TimeZoneBinary on game close 2024-02-17 16:00:14 +00:00
e2e0916100 Merge branch 'yuzu-emu:master' into import-firmware 2024-02-17 23:36:43 +11:00
501e3ae05a Implement In-app firmware installation. 2024-02-17 23:33:55 +11:00
ac33847b30 hid_core: Prevent crash if we try to iterate through empty color devices list 2024-02-16 21:11:47 -05:00
18494b0ad6 hid_core: Use dedicated "port" for android's input overlay 2024-02-16 21:09:42 -05:00
dc2c302a84 config: Reset per-game profile name on load if empty 2024-02-16 21:07:03 -05:00
a251f77556 android: Allow SettingsItems to use String or StringRes 2024-02-16 21:04:26 -05:00
ec02a1cfe5 service: erpt: Implement SubmitContext 2024-02-16 12:22:09 -06:00
39b958ab86 service: caps: Implement GetAlbumFIleList 2024-02-16 12:15:37 -06:00
dbcc447f43 service: am: Fix GetMainAppletAvailableUsers for user creation 2024-02-16 12:13:10 -06:00
2954c01b47 service: am: Add QLaunch launcher 2024-02-16 12:13:10 -06:00
af42482565 kernel: add and enable system suspend type 2024-02-14 17:03:50 -05:00
205 changed files with 5200 additions and 4228 deletions

View File

@ -5,9 +5,11 @@
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13000](https://github.com/yuzu-emu/yuzu//pull/13000) | [`461eaca7e`](https://github.com/yuzu-emu/yuzu//pull/13000/files) | device_memory_manager: skip unregistered interfaces on invalidate | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13006](https://github.com/yuzu-emu/yuzu//pull/13006) | [`3067bfd12`](https://github.com/yuzu-emu/yuzu//pull/13006/files) | buffer_cache: use mapped range with large vertex buffer size | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13017](https://github.com/yuzu-emu/yuzu//pull/13017) | [`af4248256`](https://github.com/yuzu-emu/yuzu//pull/13017/files) | kernel: add and enable system suspend type | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13026](https://github.com/yuzu-emu/yuzu//pull/13026) | [`462ea921e`](https://github.com/yuzu-emu/yuzu//pull/13026/files) | shader_recompiler: fix non-const offset for arrayed image types | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13034](https://github.com/yuzu-emu/yuzu//pull/13034) | [`50ecad547`](https://github.com/yuzu-emu/yuzu//pull/13034/files) | android: Input mapping | [t895](https://github.com/t895/) | Yes |
| [13030](https://github.com/yuzu-emu/yuzu//pull/13030) | [`4cbafc1ef`](https://github.com/yuzu-emu/yuzu//pull/13030/files) | service: audio: Rewrite IAudioController to new IPC | [german77](https://github.com/german77/) | Yes |
| [13035](https://github.com/yuzu-emu/yuzu//pull/13035) | [`940a71422`](https://github.com/yuzu-emu/yuzu//pull/13035/files) | vi: manage resources independently of nvnflinger and refactor | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13048](https://github.com/yuzu-emu/yuzu//pull/13048) | [`4cdf18095`](https://github.com/yuzu-emu/yuzu//pull/13048/files) | ns: rewrite for new IPC | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13070](https://github.com/yuzu-emu/yuzu//pull/13070) | [`911ee8fd1`](https://github.com/yuzu-emu/yuzu//pull/13070/files) | am: account for offset in transfer memory storage | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.

View File

@ -3,24 +3,21 @@
package org.yuzu.yuzu_emu
import android.app.Dialog
import android.content.DialogInterface
import android.net.Uri
import android.os.Bundle
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.Surface
import android.view.View
import android.widget.TextView
import androidx.annotation.Keep
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.lang.ref.WeakReference
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.Patch
import org.yuzu.yuzu_emu.model.GameVerificationResult
@ -184,46 +181,13 @@ object NativeLibrary {
ErrorUnknown
}
private var coreErrorAlertResult = false
private val coreErrorAlertLock = Object()
class CoreErrorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val title = requireArguments().serializable<String>("title")
val message = requireArguments().serializable<String>("message")
return MaterialAlertDialogBuilder(requireActivity())
.setTitle(title)
.setMessage(message)
.setPositiveButton(R.string.continue_button, null)
.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
coreErrorAlertResult = false
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
}
.create()
}
override fun onDismiss(dialog: DialogInterface) {
coreErrorAlertResult = true
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
}
companion object {
fun newInstance(title: String?, message: String?): CoreErrorDialogFragment {
val frag = CoreErrorDialogFragment()
val args = Bundle()
args.putString("title", title)
args.putString("message", message)
frag.arguments = args
return frag
}
}
}
var coreErrorAlertResult = false
val coreErrorAlertLock = Object()
private fun onCoreErrorImpl(title: String, message: String) {
val emulationActivity = sEmulationActivity.get()
if (emulationActivity == null) {
error("[NativeLibrary] EmulationActivity not present")
Log.error("[NativeLibrary] EmulationActivity not present")
return
}
@ -239,7 +203,7 @@ object NativeLibrary {
fun onCoreError(error: CoreError?, details: String): Boolean {
val emulationActivity = sEmulationActivity.get()
if (emulationActivity == null) {
error("[NativeLibrary] EmulationActivity not present")
Log.error("[NativeLibrary] EmulationActivity not present")
return false
}
@ -270,7 +234,7 @@ object NativeLibrary {
}
// Show the AlertDialog on the main thread.
emulationActivity.runOnUiThread(Runnable { onCoreErrorImpl(title, message) })
emulationActivity.runOnUiThread { onCoreErrorImpl(title, message) }
// Wait for the lock to notify that it is complete.
synchronized(coreErrorAlertLock) { coreErrorAlertLock.wait() }

View File

@ -80,8 +80,14 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
super.onCreate(savedInstanceState)
InputHandler.updateControllerData()
val playerOne = NativeConfig.getInputSettings(true)[0]
if (!playerOne.hasMapping() && InputHandler.androidControllers.isNotEmpty()) {
val players = NativeConfig.getInputSettings(true)
var hasConfiguredControllers = false
players.forEach {
if (it.hasMapping()) {
hasConfiguredControllers = true
}
}
if (!hasConfiguredControllers && InputHandler.androidControllers.isNotEmpty()) {
var params: ParamPackage? = null
for (controller in InputHandler.registeredControllers) {
if (controller.get("port", -1) == 0) {

View File

@ -3,15 +3,15 @@
package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.model.Driver
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class DriverAdapter(private val driverViewModel: DriverViewModel) :
@ -44,25 +44,15 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
}
// Delay marquee by 3s
title.postDelayed(
{
title.isSelected = true
title.ellipsize = TextUtils.TruncateAt.MARQUEE
version.isSelected = true
version.ellipsize = TextUtils.TruncateAt.MARQUEE
description.isSelected = true
description.ellipsize = TextUtils.TruncateAt.MARQUEE
},
3000
)
title.marquee()
version.marquee()
description.marquee()
title.text = model.title
version.text = model.version
description.text = model.description
if (model.title != binding.root.context.getString(R.string.system_gpu_driver)) {
buttonDelete.visibility = View.VISIBLE
} else {
buttonDelete.visibility = View.GONE
}
buttonDelete.setVisible(
model.title != binding.root.context.getString(R.string.system_gpu_driver)
)
}
}
}

View File

@ -4,7 +4,6 @@
package org.yuzu.yuzu_emu.adapters
import android.net.Uri
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
@ -12,6 +11,7 @@ import org.yuzu.yuzu_emu.databinding.CardFolderBinding
import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment
import org.yuzu.yuzu_emu.model.GameDir
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) :
@ -29,13 +29,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
override fun bind(model: GameDir) {
binding.apply {
path.text = Uri.parse(model.uriString).path
path.postDelayed(
{
path.isSelected = true
path.ellipsize = TextUtils.TruncateAt.MARQUEE
},
3000
)
path.marquee()
buttonEdit.setOnClickListener {
GameFolderPropertiesDialogFragment.newInstance(model)

View File

@ -4,7 +4,6 @@
package org.yuzu.yuzu_emu.adapters
import android.net.Uri
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
@ -27,6 +26,7 @@ import org.yuzu.yuzu_emu.databinding.CardGameBinding
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class GameAdapter(private val activity: AppCompatActivity) :
@ -44,14 +44,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ")
binding.textGameTitle.postDelayed(
{
binding.textGameTitle.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.textGameTitle.isSelected = true
},
3000
)
binding.textGameTitle.marquee()
binding.cardGame.setOnClickListener { onClick(model) }
binding.cardGame.setOnLongClickListener { onLongClick(model) }
}

View File

@ -3,21 +3,18 @@
package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.GameProperty
import org.yuzu.yuzu_emu.model.InstallableProperty
import org.yuzu.yuzu_emu.model.SubmenuProperty
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class GamePropertiesAdapter(
@ -76,23 +73,15 @@ class GamePropertiesAdapter(
)
)
binding.details.postDelayed({
binding.details.isSelected = true
binding.details.ellipsize = TextUtils.TruncateAt.MARQUEE
}, 3000)
binding.details.marquee()
if (submenuProperty.details != null) {
binding.details.visibility = View.VISIBLE
binding.details.setVisible(true)
binding.details.text = submenuProperty.details.invoke()
} else if (submenuProperty.detailsFlow != null) {
binding.details.visibility = View.VISIBLE
viewLifecycle.lifecycleScope.launch {
viewLifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
submenuProperty.detailsFlow.collect { binding.details.text = it }
}
}
binding.details.setVisible(true)
submenuProperty.detailsFlow.collect(viewLifecycle) { binding.details.text = it }
} else {
binding.details.visibility = View.GONE
binding.details.setVisible(false)
}
}
}
@ -112,14 +101,10 @@ class GamePropertiesAdapter(
)
)
if (installableProperty.install != null) {
binding.buttonInstall.visibility = View.VISIBLE
binding.buttonInstall.setOnClickListener { installableProperty.install.invoke() }
}
if (installableProperty.export != null) {
binding.buttonExport.visibility = View.VISIBLE
binding.buttonExport.setOnClickListener { installableProperty.export.invoke() }
}
binding.buttonInstall.setVisible(installableProperty.install != null)
binding.buttonInstall.setOnClickListener { installableProperty.install?.invoke() }
binding.buttonExport.setVisible(installableProperty.export != null)
binding.buttonExport.setOnClickListener { installableProperty.export?.invoke() }
}
}

View File

@ -3,22 +3,19 @@
package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class HomeSettingAdapter(
@ -59,18 +56,8 @@ class HomeSettingAdapter(
binding.optionIcon.alpha = 0.5f
}
viewLifecycle.lifecycleScope.launch {
viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
model.details.collect { updateOptionDetails(it) }
}
}
binding.optionDetail.postDelayed(
{
binding.optionDetail.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.optionDetail.isSelected = true
},
3000
)
model.details.collect(viewLifecycle) { updateOptionDetails(it) }
binding.optionDetail.marquee()
binding.root.setOnClickListener { onClick(model) }
}
@ -90,7 +77,7 @@ class HomeSettingAdapter(
private fun updateOptionDetails(detailString: String) {
if (detailString.isNotEmpty()) {
binding.optionDetail.text = detailString
binding.optionDetail.visibility = View.VISIBLE
binding.optionDetail.setVisible(true)
}
}
}

View File

@ -4,10 +4,10 @@
package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
import org.yuzu.yuzu_emu.model.Installable
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class InstallableAdapter(installables: List<Installable>) :
@ -26,14 +26,10 @@ class InstallableAdapter(installables: List<Installable>) :
binding.title.setText(model.titleId)
binding.description.setText(model.descriptionId)
if (model.install != null) {
binding.buttonInstall.visibility = View.VISIBLE
binding.buttonInstall.setOnClickListener { model.install.invoke() }
}
if (model.export != null) {
binding.buttonExport.visibility = View.VISIBLE
binding.buttonExport.setOnClickListener { model.export.invoke() }
}
binding.buttonInstall.setVisible(model.install != null)
binding.buttonInstall.setOnClickListener { model.install?.invoke() }
binding.buttonExport.setVisible(model.export != null)
binding.buttonExport.setOnClickListener { model.export?.invoke() }
}
}
}

View File

@ -4,12 +4,12 @@
package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
import org.yuzu.yuzu_emu.model.License
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) :
@ -25,7 +25,7 @@ class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<Lic
binding.apply {
textSettingName.text = root.context.getString(model.titleId)
textSettingDescription.text = root.context.getString(model.descriptionId)
textSettingValue.visibility = View.GONE
textSettingValue.setVisible(false)
root.setOnClickListener { onClick(model) }
}

View File

@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.adapters
import android.text.Html
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
@ -17,6 +16,7 @@ import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage
import org.yuzu.yuzu_emu.model.StepState
import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
@ -30,8 +30,8 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
AbstractViewHolder<SetupPage>(binding), SetupCallback {
override fun bind(model: SetupPage) {
if (model.stepCompleted.invoke() == StepState.COMPLETE) {
binding.buttonAction.visibility = View.INVISIBLE
binding.textConfirmation.visibility = View.VISIBLE
binding.buttonAction.setVisible(visible = false, gone = false)
binding.textConfirmation.setVisible(true)
}
binding.icon.setImageDrawable(

View File

@ -11,16 +11,13 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogInputProfilesBinding
import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.utils.collect
class InputProfileDialogFragment : DialogFragment() {
private var position = 0
@ -110,25 +107,21 @@ class InputProfileDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldShowDeleteProfileDialog.collect {
if (it.isNotEmpty()) {
MessageDialogFragment.newInstance(
activity = requireActivity(),
titleId = R.string.delete_input_profile,
descriptionId = R.string.delete_input_profile_description,
positiveAction = {
setting.deleteProfile(it)
settingsViewModel.setReloadListAndNotifyDataset(true)
},
negativeAction = {},
negativeButtonTitleId = android.R.string.cancel
).show(parentFragmentManager, MessageDialogFragment.TAG)
settingsViewModel.setShouldShowDeleteProfileDialog("")
dismiss()
}
}
settingsViewModel.shouldShowDeleteProfileDialog.collect(viewLifecycleOwner) {
if (it.isNotEmpty()) {
MessageDialogFragment.newInstance(
activity = requireActivity(),
titleId = R.string.delete_input_profile,
descriptionId = R.string.delete_input_profile_description,
positiveAction = {
setting.deleteProfile(it)
settingsViewModel.setReloadListAndNotifyDataset(true)
},
negativeAction = {},
negativeButtonTitleId = android.R.string.cancel
).show(parentFragmentManager, MessageDialogFragment.TAG)
settingsViewModel.setShouldShowDeleteProfileDialog("")
dismiss()
}
}
}

View File

@ -13,14 +13,9 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.navArgs
import com.google.android.material.color.MaterialColors
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.NativeLibrary
import java.io.IOException
import org.yuzu.yuzu_emu.R
@ -70,39 +65,23 @@ class SettingsActivity : AppCompatActivity() {
)
}
lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldRecreate.collectLatest {
if (it) {
settingsViewModel.setShouldRecreate(false)
recreate()
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldNavigateBack.collectLatest {
if (it) {
settingsViewModel.setShouldNavigateBack(false)
navigateBack()
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldShowResetSettingsDialog.collectLatest {
if (it) {
settingsViewModel.setShouldShowResetSettingsDialog(false)
ResetSettingsDialogFragment().show(
supportFragmentManager,
ResetSettingsDialogFragment.TAG
)
}
}
}
settingsViewModel.shouldRecreate.collect(
this,
resetState = { settingsViewModel.setShouldRecreate(false) }
) { if (it) recreate() }
settingsViewModel.shouldNavigateBack.collect(
this,
resetState = { settingsViewModel.setShouldNavigateBack(false) }
) { if (it) navigateBack() }
settingsViewModel.shouldShowResetSettingsDialog.collect(
this,
resetState = { settingsViewModel.setShouldShowResetSettingsDialog(false) }
) {
if (it) {
ResetSettingsDialogFragment().show(
supportFragmentManager,
ResetSettingsDialogFragment.TAG
)
}
}

View File

@ -11,12 +11,8 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.features.input.NativeInput
@ -29,6 +25,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.utils.ParamPackage
import org.yuzu.yuzu_emu.utils.collect
class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener {
private var type = 0
@ -169,17 +166,11 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
super.onViewCreated(view, savedInstanceState)
when (type) {
SettingsItem.TYPE_SLIDER -> {
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.sliderTextValue.collect {
sliderBinding.textValue.text = it
}
}
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.sliderProgress.collect {
sliderBinding.slider.value = it.toFloat()
}
}
settingsViewModel.sliderTextValue.collect(viewLifecycleOwner) {
sliderBinding.textValue.text = it
}
settingsViewModel.sliderProgress.collect(viewLifecycleOwner) {
sliderBinding.slider.value = it.toFloat()
}
}
}

View File

@ -13,21 +13,17 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class SettingsFragment : Fragment() {
private lateinit var presenter: SettingsFragmentPresenter
@ -63,8 +59,7 @@ class SettingsFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector", "NotifyDataSetChanged")
@SuppressLint("NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
settingsAdapter = SettingsAdapter(this, requireContext())
@ -100,65 +95,37 @@ class SettingsFragment : Fragment() {
settingsViewModel.setShouldNavigateBack(true)
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldReloadSettingsList.collectLatest {
if (it) {
settingsViewModel.setShouldReloadSettingsList(false)
presenter.loadSettingsList()
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
settingsViewModel.adapterItemChanged.collect {
if (it != -1) {
settingsAdapter?.notifyItemChanged(it)
settingsViewModel.setAdapterItemChanged(-1)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
settingsViewModel.datasetChanged.collect {
if (it) {
settingsAdapter?.notifyDataSetChanged()
settingsViewModel.setDatasetChanged(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.reloadListAndNotifyDataset.collectLatest {
if (it) {
settingsViewModel.setReloadListAndNotifyDataset(false)
presenter.loadSettingsList(true)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldShowResetInputDialog.collectLatest {
if (it) {
MessageDialogFragment.newInstance(
activity = requireActivity(),
titleId = R.string.reset_mapping,
descriptionId = R.string.reset_mapping_description,
positiveAction = {
NativeInput.resetControllerMappings(getPlayerIndex())
settingsViewModel.setReloadListAndNotifyDataset(true)
},
negativeAction = {}
).show(parentFragmentManager, MessageDialogFragment.TAG)
settingsViewModel.setShouldShowResetInputDialog(false)
}
}
}
settingsViewModel.shouldReloadSettingsList.collect(
viewLifecycleOwner,
resetState = { settingsViewModel.setShouldReloadSettingsList(false) }
) { if (it) presenter.loadSettingsList() }
settingsViewModel.adapterItemChanged.collect(
viewLifecycleOwner,
resetState = { settingsViewModel.setAdapterItemChanged(-1) }
) { if (it != -1) settingsAdapter?.notifyItemChanged(it) }
settingsViewModel.datasetChanged.collect(
viewLifecycleOwner,
resetState = { settingsViewModel.setDatasetChanged(false) }
) { if (it) settingsAdapter?.notifyDataSetChanged() }
settingsViewModel.reloadListAndNotifyDataset.collect(
viewLifecycleOwner,
resetState = { settingsViewModel.setReloadListAndNotifyDataset(false) }
) { if (it) presenter.loadSettingsList(true) }
settingsViewModel.shouldShowResetInputDialog.collect(
viewLifecycleOwner,
resetState = { settingsViewModel.setShouldShowResetInputDialog(false) }
) {
if (it) {
MessageDialogFragment.newInstance(
activity = requireActivity(),
titleId = R.string.reset_mapping,
descriptionId = R.string.reset_mapping_description,
positiveAction = {
NativeInput.resetControllerMappings(getPlayerIndex())
settingsViewModel.setReloadListAndNotifyDataset(true)
},
negativeAction = {}
).show(parentFragmentManager, MessageDialogFragment.TAG)
}
}

View File

@ -15,19 +15,17 @@ import androidx.core.view.updatePadding
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.transition.MaterialSharedAxis
import info.debatty.java.stringsimilarity.Cosine
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class SettingsSearchFragment : Fragment() {
private var _binding: FragmentSettingsSearchBinding? = null
@ -83,14 +81,10 @@ class SettingsSearchFragment : Fragment() {
search()
binding.settingsList.smoothScrollToPosition(0)
}
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldReloadSettingsList.collect {
if (it) {
settingsViewModel.setShouldReloadSettingsList(false)
search()
}
}
settingsViewModel.shouldReloadSettingsList.collect(viewLifecycleOwner) {
if (it) {
settingsViewModel.setShouldReloadSettingsList(false)
search()
}
}
@ -106,10 +100,9 @@ class SettingsSearchFragment : Fragment() {
private fun search() {
val searchTerm = binding.searchText.text.toString().lowercase()
binding.clearButton.visibility =
if (searchTerm.isEmpty()) View.INVISIBLE else View.VISIBLE
binding.clearButton.setVisible(visible = searchTerm.isNotEmpty(), gone = false)
if (searchTerm.isEmpty()) {
binding.noResultsView.visibility = View.VISIBLE
binding.noResultsView.setVisible(visible = false, gone = false)
settingsAdapter?.submitList(emptyList())
return
}
@ -136,8 +129,7 @@ class SettingsSearchFragment : Fragment() {
optionalSetting
}
settingsAdapter?.submitList(sortedList)
binding.noResultsView.visibility =
if (sortedList.isEmpty()) View.VISIBLE else View.INVISIBLE
binding.noResultsView.setVisible(visible = sortedList.isEmpty(), gone = false)
}
private fun focusSearch() {

View File

@ -14,6 +14,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
@ -22,27 +23,18 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun bind(item: SettingsItem) {
setting = item as DateTimeSetting
binding.textSettingName.text = item.title
if (setting.description.isNotEmpty()) {
binding.textSettingDescription.text = item.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
binding.textSettingDescription.text = item.description
binding.textSettingValue.setVisible(true)
val epochTime = setting.getValue()
val instant = Instant.ofEpochMilli(epochTime * 1000)
val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingValue.text = dateFormatter.format(zonedTime)
binding.buttonClear.visibility = if (setting.setting.global ||
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setVisible(
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}

View File

@ -9,6 +9,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
@ -20,10 +21,10 @@ class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: Setti
binding.textSettingValue.text =
setting.getCurrentProfile().ifEmpty { binding.root.context.getString(R.string.not_set) }
binding.textSettingDescription.visibility = View.GONE
binding.buttonClear.visibility = View.GONE
binding.icon.visibility = View.GONE
binding.buttonClear.visibility = View.GONE
binding.textSettingDescription.setVisible(false)
binding.buttonClear.setVisible(false)
binding.icon.setVisible(false)
binding.buttonClear.setVisible(false)
}
override fun onClick(clicked: View) =

View File

@ -12,6 +12,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.InputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.ModifierInputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
@ -22,38 +23,26 @@ class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: Setting
binding.textSettingName.text = setting.title
binding.textSettingValue.text = setting.getSelectedValue()
binding.buttonOptions.visibility = when (item) {
when (item) {
is AnalogInputSetting -> {
val param = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog)
if (
binding.buttonOptions.setVisible(
param.get("engine", "") == "analog_from_button" ||
param.has("axis_x") || param.has("axis_y")
) {
View.VISIBLE
} else {
View.GONE
}
param.has("axis_x") || param.has("axis_y")
)
}
is ButtonInputSetting -> {
val param = NativeInput.getButtonParam(item.playerIndex, item.nativeButton)
if (
binding.buttonOptions.setVisible(
param.has("code") || param.has("button") || param.has("hat") ||
param.has("axis")
) {
View.VISIBLE
} else {
View.GONE
}
param.has("axis")
)
}
is ModifierInputSetting -> {
val params = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog)
if (params.has("modifier")) {
View.VISIBLE
} else {
View.GONE
}
binding.buttonOptions.setVisible(params.has("modifier"))
}
}

View File

@ -9,6 +9,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
@ -16,8 +17,8 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun bind(item: SettingsItem) {
setting = item as RunnableSetting
binding.icon.setVisible(setting.iconId != 0)
if (setting.iconId != 0) {
binding.icon.visibility = View.VISIBLE
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.resources,
@ -25,19 +26,13 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
binding.icon.context.theme
)
)
} else {
binding.icon.visibility = View.GONE
}
binding.textSettingName.text = setting.title
if (setting.description.isNotEmpty()) {
binding.textSettingDescription.setText(item.descriptionId)
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.GONE
binding.buttonClear.visibility = View.GONE
binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.text = item.description
binding.textSettingValue.setVisible(false)
binding.buttonClear.setVisible(false)
setStyle(setting.isEditable, binding)
}

View File

@ -11,6 +11,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
@ -19,14 +20,10 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
override fun bind(item: SettingsItem) {
setting = item
binding.textSettingName.text = setting.title
if (item.description.isNotEmpty()) {
binding.textSettingDescription.text = item.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
binding.textSettingDescription.text = item.description
binding.textSettingValue.visibility = View.VISIBLE
binding.textSettingValue.setVisible(true)
when (item) {
is SingleChoiceSetting -> {
val resMgr = binding.textSettingValue.context.resources
@ -48,16 +45,12 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
}
}
if (binding.textSettingValue.text.isEmpty()) {
binding.textSettingValue.visibility = View.GONE
binding.textSettingValue.setVisible(false)
}
binding.buttonClear.visibility = if (setting.setting.global ||
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setVisible(
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}

View File

@ -10,6 +10,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
@ -18,26 +19,18 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
override fun bind(item: SettingsItem) {
setting = item as SliderSetting
binding.textSettingName.text = setting.title
if (item.description.isNotEmpty()) {
binding.textSettingDescription.text = setting.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
binding.textSettingDescription.text = setting.description
binding.textSettingValue.setVisible(true)
binding.textSettingValue.text = String.format(
binding.textSettingValue.context.getString(R.string.value_with_units),
setting.getSelectedValue(),
setting.units
)
binding.buttonClear.visibility = if (setting.setting.global ||
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setVisible(
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}

View File

@ -9,6 +9,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
@ -16,8 +17,8 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
override fun bind(item: SettingsItem) {
setting = item as SubmenuSetting
binding.icon.setVisible(setting.iconId != 0)
if (setting.iconId != 0) {
binding.icon.visibility = View.VISIBLE
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.resources,
@ -25,19 +26,13 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
binding.icon.context.theme
)
)
} else {
binding.icon.visibility = View.GONE
}
binding.textSettingName.text = setting.title
if (setting.description.isNotEmpty()) {
binding.textSettingDescription.text = setting.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.GONE
binding.buttonClear.visibility = View.GONE
binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.text = setting.description
binding.textSettingValue.setVisible(false)
binding.buttonClear.setVisible(false)
}
override fun onClick(clicked: View) {

View File

@ -10,6 +10,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
@ -19,12 +20,8 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
override fun bind(item: SettingsItem) {
setting = item as SwitchSetting
binding.textSettingName.text = setting.title
if (setting.description.isNotEmpty()) {
binding.textSettingDescription.text = setting.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.text = setting.description
binding.switchWidget.setOnCheckedChangeListener(null)
binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal)
@ -32,13 +29,9 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
}
binding.buttonClear.visibility = if (setting.setting.global ||
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setVisible(
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
@ -16,9 +15,6 @@ import androidx.core.view.updatePadding
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
@ -32,6 +28,7 @@ import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.AddonUtil
import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.File
class AddonsFragment : Fragment() {
@ -60,8 +57,6 @@ class AddonsFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = false)
@ -78,57 +73,41 @@ class AddonsFragment : Fragment() {
adapter = AddonAdapter(addonViewModel)
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.addonList.collect {
(binding.listAddons.adapter as AddonAdapter).submitList(it)
}
}
addonViewModel.addonList.collect(viewLifecycleOwner) {
(binding.listAddons.adapter as AddonAdapter).submitList(it)
}
addonViewModel.showModInstallPicker.collect(
viewLifecycleOwner,
resetState = { addonViewModel.showModInstallPicker(false) }
) { if (it) installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) }
addonViewModel.showModNoticeDialog.collect(
viewLifecycleOwner,
resetState = { addonViewModel.showModNoticeDialog(false) }
) {
if (it) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.addon_notice,
descriptionId = R.string.addon_notice_description,
dismissible = false,
positiveAction = { addonViewModel.showModInstallPicker(true) },
negativeAction = {},
negativeButtonTitleId = R.string.close
).show(parentFragmentManager, MessageDialogFragment.TAG)
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.showModInstallPicker.collect {
if (it) {
installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
addonViewModel.showModInstallPicker(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.showModNoticeDialog.collect {
if (it) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.addon_notice,
descriptionId = R.string.addon_notice_description,
dismissible = false,
positiveAction = { addonViewModel.showModInstallPicker(true) },
negativeAction = {},
negativeButtonTitleId = R.string.close
).show(parentFragmentManager, MessageDialogFragment.TAG)
addonViewModel.showModNoticeDialog(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.addonToDelete.collect {
if (it != null) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.confirm_uninstall,
descriptionId = R.string.confirm_uninstall_description,
positiveAction = { addonViewModel.onDeleteAddon(it) },
negativeAction = {}
).show(parentFragmentManager, MessageDialogFragment.TAG)
addonViewModel.setAddonToDelete(null)
}
}
}
}
addonViewModel.addonToDelete.collect(
viewLifecycleOwner,
resetState = { addonViewModel.setAddonToDelete(null) }
) {
if (it != null) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.confirm_uninstall,
descriptionId = R.string.confirm_uninstall_description,
positiveAction = { addonViewModel.onDeleteAddon(it) },
negativeAction = {}
).show(parentFragmentManager, MessageDialogFragment.TAG)
}
}

View File

@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
class CoreErrorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
MaterialAlertDialogBuilder(requireActivity())
.setTitle(requireArguments().getString(TITLE))
.setMessage(requireArguments().getString(MESSAGE))
.setPositiveButton(R.string.continue_button, null)
.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
NativeLibrary.coreErrorAlertResult = false
synchronized(NativeLibrary.coreErrorAlertLock) {
NativeLibrary.coreErrorAlertLock.notify()
}
}
.create()
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
NativeLibrary.coreErrorAlertResult = true
synchronized(NativeLibrary.coreErrorAlertLock) { NativeLibrary.coreErrorAlertLock.notify() }
}
companion object {
const val TITLE = "Title"
const val MESSAGE = "Message"
fun newInstance(title: String, message: String): CoreErrorDialogFragment {
val frag = CoreErrorDialogFragment()
val args = Bundle()
args.putString(TITLE, title)
args.putString(MESSAGE, message)
frag.arguments = args
return frag
}
}
}

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -14,9 +13,6 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager
@ -35,6 +31,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.File
import java.io.IOException
@ -63,8 +60,6 @@ class DriverManagerFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true)
@ -89,15 +84,8 @@ class DriverManagerFragment : Fragment() {
}
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
driverViewModel.showClearButton.collect {
binding.toolbarDrivers.menu
.findItem(R.id.menu_driver_use_global).isVisible = it
}
}
}
driverViewModel.showClearButton.collect(viewLifecycleOwner) {
binding.toolbarDrivers.menu.findItem(R.id.menu_driver_use_global).isVisible = it
}
}

View File

@ -10,14 +10,11 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.collect
class DriversLoadingDialogFragment : DialogFragment() {
private val driverViewModel: DriverViewModel by activityViewModels()
@ -44,13 +41,7 @@ class DriversLoadingDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isInteractionAllowed.collect { if (it) dismiss() }
}
}
}
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) { if (it) dismiss() }
}
companion object {

View File

@ -32,9 +32,6 @@ import androidx.drawerlayout.widget.DrawerLayout
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.window.layout.FoldingFeature
@ -42,9 +39,6 @@ import androidx.window.layout.WindowInfoTracker
import androidx.window.layout.WindowLayoutInfo
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
@ -63,6 +57,7 @@ import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import java.lang.NullPointerException
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@ -90,14 +85,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (context is EmulationActivity) {
emulationActivity = context
NativeLibrary.setEmulationActivity(context)
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(context)
.windowLayoutInfo(context)
.collect { updateFoldableLayout(context, it) }
}
}
} else {
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
}
@ -168,8 +155,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (requireActivity().isFinishing) {
@ -350,129 +335,86 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.loadingTitle.isSelected = true
binding.loadingText.isSelected = true
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(requireContext())
.windowLayoutInfo(requireActivity())
.collect {
updateFoldableLayout(requireActivity() as EmulationActivity, it)
}
}
WindowInfoTracker.getOrCreate(requireContext())
.windowLayoutInfo(requireActivity()).collect(viewLifecycleOwner) {
updateFoldableLayout(requireActivity() as EmulationActivity, it)
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.shaderProgress.collectLatest {
if (it > 0 && it != emulationViewModel.totalShaders.value) {
binding.loadingProgressIndicator.isIndeterminate = false
emulationViewModel.shaderProgress.collect(viewLifecycleOwner) {
if (it > 0 && it != emulationViewModel.totalShaders.value) {
binding.loadingProgressIndicator.isIndeterminate = false
if (it < binding.loadingProgressIndicator.max) {
binding.loadingProgressIndicator.progress = it
}
}
if (it < binding.loadingProgressIndicator.max) {
binding.loadingProgressIndicator.progress = it
}
}
if (it == emulationViewModel.totalShaders.value) {
binding.loadingText.setText(R.string.loading)
binding.loadingProgressIndicator.isIndeterminate = true
}
}
}
if (it == emulationViewModel.totalShaders.value) {
binding.loadingText.setText(R.string.loading)
binding.loadingProgressIndicator.isIndeterminate = true
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.totalShaders.collectLatest {
binding.loadingProgressIndicator.max = it
}
}
}
emulationViewModel.totalShaders.collect(viewLifecycleOwner) {
binding.loadingProgressIndicator.max = it
}
emulationViewModel.shaderMessage.collect(viewLifecycleOwner) {
if (it.isNotEmpty()) {
binding.loadingText.text = it
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.shaderMessage.collectLatest {
if (it.isNotEmpty()) {
binding.loadingText.text = it
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isInteractionAllowed.collect {
if (it) {
startEmulation()
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.emulationStarted.collectLatest {
if (it) {
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
ViewUtils.showView(binding.surfaceInputOverlay)
ViewUtils.hideView(binding.loadingIndicator)
}
emulationState.updateSurface()
emulationViewModel.emulationStarted.collect(viewLifecycleOwner) {
if (it) {
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
ViewUtils.showView(binding.surfaceInputOverlay)
ViewUtils.hideView(binding.loadingIndicator)
// Setup overlays
updateShowFpsOverlay()
updateThermalOverlay()
}
}
}
emulationState.updateSurface()
// Setup overlays
updateShowFpsOverlay()
updateThermalOverlay()
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.isEmulationStopping.collectLatest {
if (it) {
binding.loadingText.setText(R.string.shutting_down)
ViewUtils.showView(binding.loadingIndicator)
ViewUtils.hideView(binding.inputContainer)
ViewUtils.hideView(binding.showFpsText)
}
}
}
}
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
if (it) {
binding.loadingText.setText(R.string.shutting_down)
ViewUtils.showView(binding.loadingIndicator)
ViewUtils.hideView(binding.inputContainer)
ViewUtils.hideView(binding.showFpsText)
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.drawerOpen.collect {
if (it) {
binding.drawerLayout.open()
binding.inGameMenu.requestFocus()
} else {
binding.drawerLayout.close()
}
}
}
}
emulationViewModel.drawerOpen.collect(viewLifecycleOwner) {
if (it) {
binding.drawerLayout.open()
binding.inGameMenu.requestFocus()
} else {
binding.drawerLayout.close()
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.programChanged.collect {
if (it != 0) {
emulationViewModel.setEmulationStarted(false)
binding.drawerLayout.close()
binding.drawerLayout
.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
ViewUtils.hideView(binding.surfaceInputOverlay)
ViewUtils.showView(binding.loadingIndicator)
}
}
}
}
emulationViewModel.programChanged.collect(viewLifecycleOwner) {
if (it != 0) {
emulationViewModel.setEmulationStarted(false)
binding.drawerLayout.close()
binding.drawerLayout
.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
ViewUtils.hideView(binding.surfaceInputOverlay)
ViewUtils.showView(binding.loadingIndicator)
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.emulationStopped.collect {
if (it && emulationViewModel.programChanged.value != -1) {
if (perfStatsUpdater != null) {
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
}
emulationState.changeProgram(emulationViewModel.programChanged.value)
emulationViewModel.setProgramChanged(-1)
emulationViewModel.setEmulationStopped(false)
}
}
}
emulationViewModel.emulationStopped.collect(viewLifecycleOwner) {
if (it && emulationViewModel.programChanged.value != -1) {
if (perfStatsUpdater != null) {
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
}
emulationState.changeProgram(emulationViewModel.programChanged.value)
emulationViewModel.setProgramChanged(-1)
emulationViewModel.setEmulationStopped(false)
}
}
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) {
if (it) startEmulation()
}
}
private fun startEmulation(programIndex: Int = 0) {
@ -500,14 +442,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.drawerLayout.close()
}
if (showInputOverlay) {
binding.surfaceInputOverlay.visibility = View.INVISIBLE
binding.surfaceInputOverlay.setVisible(visible = false, gone = false)
}
} else {
if (showInputOverlay && emulationViewModel.emulationStarted.value) {
binding.surfaceInputOverlay.visibility = View.VISIBLE
} else {
binding.surfaceInputOverlay.visibility = View.INVISIBLE
}
binding.surfaceInputOverlay.setVisible(
showInputOverlay && emulationViewModel.emulationStarted.value
)
if (!isInFoldableLayout) {
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
binding.surfaceInputOverlay.layout = OverlayLayout.Portrait
@ -544,7 +484,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
private fun updateShowFpsOverlay() {
if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) {
val showOverlay = BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
binding.showFpsText.setVisible(showOverlay)
if (showOverlay) {
val SYSTEM_FPS = 0
val FPS = 1
val FRAMETIME = 2
@ -564,17 +506,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
perfStatsUpdateHandler.post(perfStatsUpdater!!)
binding.showFpsText.visibility = View.VISIBLE
} else {
if (perfStatsUpdater != null) {
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
}
binding.showFpsText.visibility = View.GONE
}
}
private fun updateThermalOverlay() {
if (BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()) {
val showOverlay = BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
binding.showThermalsText.setVisible(showOverlay)
if (showOverlay) {
thermalStatsUpdater = {
if (emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value
@ -596,12 +538,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
binding.showThermalsText.visibility = View.VISIBLE
} else {
if (thermalStatsUpdater != null) {
thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!)
}
binding.showThermalsText.visibility = View.GONE
}
}
@ -870,12 +810,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
}
binding.doneControlConfig.visibility = View.VISIBLE
binding.doneControlConfig.setVisible(false)
binding.surfaceInputOverlay.setIsInEditMode(true)
}
private fun stopConfiguringControls() {
binding.doneControlConfig.visibility = View.GONE
binding.doneControlConfig.setVisible(false)
binding.surfaceInputOverlay.setIsInEditMode(false)
// Unlock the orientation if it was locked for editing
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) {

View File

@ -13,9 +13,6 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
@ -27,6 +24,7 @@ import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class GameFoldersFragment : Fragment() {
private var _binding: FragmentFoldersBinding? = null
@ -70,12 +68,8 @@ class GameFoldersFragment : Fragment() {
adapter = FolderAdapter(requireActivity(), gamesViewModel)
}
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.folders.collect {
(binding.listFolders.adapter as FolderAdapter).submitList(it)
}
}
gamesViewModel.folders.collect(viewLifecycleOwner) {
(binding.listFolders.adapter as FolderAdapter).submitList(it)
}
val mainActivity = requireActivity() as MainActivity

View File

@ -27,6 +27,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentGameInfoBinding
import org.yuzu.yuzu_emu.model.GameVerificationResult
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.GameMetadata
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class GameInfoFragment : Fragment() {
@ -85,7 +86,7 @@ class GameInfoFragment : Fragment() {
copyToClipboard(getString(R.string.developer), args.game.developer)
}
} else {
developer.visibility = View.GONE
developer.setVisible(false)
}
version.setHint(R.string.version)

View File

@ -3,11 +3,9 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -18,9 +16,7 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager
@ -46,7 +42,9 @@ import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.BufferedOutputStream
import java.io.File
@ -76,8 +74,6 @@ class GamePropertiesFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true)
@ -107,13 +103,7 @@ class GamePropertiesFragment : Fragment() {
GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen)
binding.title.text = args.game.title
binding.title.postDelayed(
{
binding.title.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.title.isSelected = true
},
3000
)
binding.title.marquee()
binding.buttonStart.setOnClickListener {
LaunchGameDialogFragment.newInstance(args.game)
@ -122,28 +112,14 @@ class GamePropertiesFragment : Fragment() {
reloadList()
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
homeViewModel.openImportSaves.collect {
if (it) {
importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
homeViewModel.reloadPropertiesList.collect {
if (it) {
reloadList()
homeViewModel.reloadPropertiesList(false)
}
}
}
}
}
homeViewModel.openImportSaves.collect(
viewLifecycleOwner,
resetState = { homeViewModel.setOpenImportSaves(false) }
) { if (it) importSaves.launch(arrayOf("application/zip")) }
homeViewModel.reloadPropertiesList.collect(
viewLifecycleOwner,
resetState = { homeViewModel.reloadPropertiesList(false) }
) { if (it) reloadList() }
setInsets()
}

View File

@ -14,9 +14,6 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
@ -35,6 +32,7 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.BufferedOutputStream
import java.io.File
import java.math.BigInteger
@ -75,14 +73,10 @@ class InstallableFragment : Fragment() {
binding.root.findNavController().popBackStack()
}
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.openImportSaves.collect {
if (it) {
importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false)
}
}
homeViewModel.openImportSaves.collect(viewLifecycleOwner) {
if (it) {
importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false)
}
}

View File

@ -13,15 +13,13 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.TaskViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class ProgressDialogFragment : DialogFragment() {
private val taskViewModel: TaskViewModel by activityViewModels()
@ -64,72 +62,50 @@ class ProgressDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.message.isSelected = true
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.isComplete.collect {
if (it) {
dismiss()
when (val result = taskViewModel.result.value) {
is String -> Toast.makeText(
requireContext(),
result,
Toast.LENGTH_LONG
).show()
taskViewModel.isComplete.collect(viewLifecycleOwner) {
if (it) {
dismiss()
when (val result = taskViewModel.result.value) {
is String -> Toast.makeText(
requireContext(),
result,
Toast.LENGTH_LONG
).show()
is MessageDialogFragment -> result.show(
requireActivity().supportFragmentManager,
MessageDialogFragment.TAG
)
is MessageDialogFragment -> result.show(
requireActivity().supportFragmentManager,
MessageDialogFragment.TAG
)
else -> {
// Do nothing
}
}
taskViewModel.clear()
}
else -> {
// Do nothing
}
}
taskViewModel.clear()
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.cancelled.collect {
if (it) {
dialog?.setTitle(R.string.cancelling)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.progress.collect {
if (it != 0.0) {
binding.progressBar.apply {
isIndeterminate = false
progress = (
(it / taskViewModel.maxProgress.value) *
PROGRESS_BAR_RESOLUTION
).toInt()
min = 0
max = PROGRESS_BAR_RESOLUTION
}
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.message.collect {
if (it.isEmpty()) {
binding.message.visibility = View.GONE
} else {
binding.message.visibility = View.VISIBLE
binding.message.text = it
}
}
}
taskViewModel.cancelled.collect(viewLifecycleOwner) {
if (it) {
dialog?.setTitle(R.string.cancelling)
}
}
taskViewModel.progress.collect(viewLifecycleOwner) {
if (it != 0.0) {
binding.progressBar.apply {
isIndeterminate = false
progress = (
(it / taskViewModel.maxProgress.value) *
PROGRESS_BAR_RESOLUTION
).toInt()
min = 0
max = PROGRESS_BAR_RESOLUTION
}
}
}
taskViewModel.message.collect(viewLifecycleOwner) {
binding.message.setVisible(it.isNotEmpty())
binding.message.text = it
}
}
// By default, the ProgressDialog will immediately dismiss itself upon a button being pressed.

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
@ -18,14 +17,9 @@ import androidx.core.view.updatePadding
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.PreferenceManager
import info.debatty.java.stringsimilarity.Jaccard
import info.debatty.java.stringsimilarity.JaroWinkler
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import java.util.Locale
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
@ -35,6 +29,8 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null
@ -58,8 +54,6 @@ class SearchFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = true, animated = true)
@ -81,42 +75,18 @@ class SearchFragment : Fragment() {
binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() }
binding.searchText.doOnTextChanged { text: CharSequence?, _: Int, _: Int, _: Int ->
if (text.toString().isNotEmpty()) {
binding.clearButton.visibility = View.VISIBLE
} else {
binding.clearButton.visibility = View.INVISIBLE
}
binding.clearButton.setVisible(text.toString().isNotEmpty())
filterAndSearch()
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.searchFocused.collect {
if (it) {
focusSearch()
gamesViewModel.setSearchFocused(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.games.collectLatest { filterAndSearch() }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.searchedGames.collect {
(binding.gridGamesSearch.adapter as GameAdapter).submitList(it)
if (it.isEmpty()) {
binding.noResultsView.visibility = View.VISIBLE
} else {
binding.noResultsView.visibility = View.GONE
}
}
}
}
gamesViewModel.searchFocused.collect(
viewLifecycleOwner,
resetState = { gamesViewModel.setSearchFocused(false) }
) { if (it) focusSearch() }
gamesViewModel.games.collect(viewLifecycleOwner) { filterAndSearch() }
gamesViewModel.searchedGames.collect(viewLifecycleOwner) {
(binding.gridGamesSearch.adapter as GameAdapter).submitList(it)
binding.noResultsView.setVisible(it.isNotEmpty())
}
binding.clearButton.setOnClickListener { binding.searchText.setText("") }

View File

@ -4,7 +4,6 @@
package org.yuzu.yuzu_emu.fragments
import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Build
import android.os.Bundle
@ -23,9 +22,6 @@ import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.preference.PreferenceManager
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
@ -46,6 +42,8 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class SetupFragment : Fragment() {
private var _binding: FragmentSetupBinding? = null
@ -77,8 +75,6 @@ class SetupFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
mainActivity = requireActivity() as MainActivity
@ -210,28 +206,14 @@ class SetupFragment : Fragment() {
)
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.shouldPageForward.collect {
if (it) {
pageForward()
homeViewModel.setShouldPageForward(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.gamesDirSelected.collect {
if (it) {
gamesDirCallback.onStepCompleted()
homeViewModel.setGamesDirSelected(false)
}
}
}
}
}
homeViewModel.shouldPageForward.collect(
viewLifecycleOwner,
resetState = { homeViewModel.setShouldPageForward(false) }
) { if (it) pageForward() }
homeViewModel.gamesDirSelected.collect(
viewLifecycleOwner,
resetState = { homeViewModel.setGamesDirSelected(false) }
) { if (it) gamesDirCallback.onStepCompleted() }
binding.viewPager2.apply {
adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages)
@ -292,12 +274,8 @@ class SetupFragment : Fragment() {
val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY)
hasBeenWarned = savedInstanceState.getBooleanArray(KEY_HAS_BEEN_WARNED)!!
if (nextIsVisible) {
binding.buttonNext.visibility = View.VISIBLE
}
if (backIsVisible) {
binding.buttonBack.visibility = View.VISIBLE
}
binding.buttonNext.setVisible(nextIsVisible)
binding.buttonBack.setVisible(backIsVisible)
} else {
hasBeenWarned = BooleanArray(pages.size)
}

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.ui
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -14,19 +13,16 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.color.MaterialColors
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.GameAdapter
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class GamesFragment : Fragment() {
private var _binding: FragmentGamesBinding? = null
@ -44,8 +40,6 @@ class GamesFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = true, animated = true)
@ -88,49 +82,28 @@ class GamesFragment : Fragment() {
}
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.isReloading.collect {
binding.swipeRefresh.isRefreshing = it
if (gamesViewModel.games.value.isEmpty() && !it) {
binding.noticeText.visibility = View.VISIBLE
} else {
binding.noticeText.visibility = View.INVISIBLE
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.games.collectLatest {
(binding.gridGames.adapter as GameAdapter).submitList(it)
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.shouldSwapData.collect {
if (it) {
(binding.gridGames.adapter as GameAdapter).submitList(
gamesViewModel.games.value
)
gamesViewModel.setShouldSwapData(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.shouldScrollToTop.collect {
if (it) {
scrollToTop()
gamesViewModel.setShouldScrollToTop(false)
}
}
}
gamesViewModel.isReloading.collect(viewLifecycleOwner) {
binding.swipeRefresh.isRefreshing = it
binding.noticeText.setVisible(
visible = gamesViewModel.games.value.isEmpty() && !it,
gone = false
)
}
gamesViewModel.games.collect(viewLifecycleOwner) {
(binding.gridGames.adapter as GameAdapter).submitList(it)
}
gamesViewModel.shouldSwapData.collect(
viewLifecycleOwner,
resetState = { gamesViewModel.setShouldSwapData(false) }
) {
if (it) {
(binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value)
}
}
gamesViewModel.shouldScrollToTop.collect(
viewLifecycleOwner,
resetState = { gamesViewModel.setShouldScrollToTop(false) }
) { if (it) scrollToTop() }
setInsets()
}

View File

@ -19,9 +19,6 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
@ -30,7 +27,6 @@ import com.google.android.material.color.MaterialColors
import com.google.android.material.navigation.NavigationBarView
import java.io.File
import java.io.FilenameFilter
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
@ -47,6 +43,7 @@ import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.model.TaskViewModel
import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.util.zip.ZipEntry
@ -139,42 +136,23 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
// Prevents navigation from being drawn for a short time on recreation if set to hidden
if (!homeViewModel.navigationVisible.value.first) {
binding.navigationView.visibility = View.INVISIBLE
binding.statusBarShade.visibility = View.INVISIBLE
binding.navigationView.setVisible(visible = false, gone = false)
binding.statusBarShade.setVisible(visible = false, gone = false)
}
lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.navigationVisible.collect { showNavigation(it.first, it.second) }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.statusBarShadeVisible.collect { showStatusBarShade(it) }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.contentToInstall.collect {
if (it != null) {
installContent(it)
homeViewModel.setContentToInstall(null)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.checkKeys.collect {
if (it) {
checkKeys()
homeViewModel.setCheckKeys(false)
}
}
}
homeViewModel.navigationVisible.collect(this) { showNavigation(it.first, it.second) }
homeViewModel.statusBarShadeVisible.collect(this) { showStatusBarShade(it) }
homeViewModel.contentToInstall.collect(
this,
resetState = { homeViewModel.setContentToInstall(null) }
) {
if (it != null) {
installContent(it)
}
}
homeViewModel.checkKeys.collect(this, resetState = { homeViewModel.setCheckKeys(false) }) {
if (it) checkKeys()
}
setInsets()
}
@ -214,18 +192,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private fun showNavigation(visible: Boolean, animated: Boolean) {
if (!animated) {
if (visible) {
binding.navigationView.visibility = View.VISIBLE
} else {
binding.navigationView.visibility = View.INVISIBLE
}
binding.navigationView.setVisible(visible)
return
}
val smallLayout = resources.getBoolean(R.bool.small_layout)
binding.navigationView.animate().apply {
if (visible) {
binding.navigationView.visibility = View.VISIBLE
binding.navigationView.setVisible(true)
duration = 300
interpolator = PathInterpolator(0.05f, 0.7f, 0.1f, 1f)
@ -264,7 +238,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}.withEndAction {
if (!visible) {
binding.navigationView.visibility = View.INVISIBLE
binding.navigationView.setVisible(visible = false, gone = false)
}
}.start()
}
@ -272,7 +246,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private fun showStatusBarShade(visible: Boolean) {
binding.statusBarShade.animate().apply {
if (visible) {
binding.statusBarShade.visibility = View.VISIBLE
binding.statusBarShade.setVisible(true)
binding.statusBarShade.translationY = binding.statusBarShade.height.toFloat() * -2
duration = 300
translationY(0f)
@ -284,7 +258,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}.withEndAction {
if (!visible) {
binding.statusBarShade.visibility = View.INVISIBLE
binding.statusBarShade.setVisible(visible = false, gone = false)
}
}.start()
}
@ -524,7 +498,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
this@MainActivity,
titleId = R.string.content_install_notice,
descriptionId = R.string.content_install_notice_description,
positiveAction = { homeViewModel.setContentToInstall(documents) }
positiveAction = { homeViewModel.setContentToInstall(documents) },
negativeAction = {}
)
}
}.show(supportFragmentManager, ProgressDialogFragment.TAG)

View File

@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
/**
* Collects this [Flow] with a given [LifecycleOwner].
* @param scope [LifecycleOwner] that this [Flow] will be collected with.
* @param repeatState When to repeat collection on this [Flow].
* @param resetState Optional lambda to reset state of an underlying [MutableStateFlow] after
* [stateCollector] has been run.
* @param stateCollector Lambda that receives new state.
*/
inline fun <reified T> Flow<T>.collect(
scope: LifecycleOwner,
repeatState: Lifecycle.State = Lifecycle.State.CREATED,
crossinline resetState: () -> Unit = {},
crossinline stateCollector: (state: T) -> Unit
) {
scope.apply {
lifecycleScope.launch {
repeatOnLifecycle(repeatState) {
this@collect.collect {
stateCollector(it)
resetState()
}
}
}
}
}

View File

@ -3,8 +3,10 @@
package org.yuzu.yuzu_emu.utils
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
object ViewUtils {
fun showView(view: View, length: Long = 300) {
@ -57,4 +59,35 @@ object ViewUtils {
}
this.layoutParams = layoutParams
}
/**
* Shows or hides a view.
* @param visible Whether a view will be made View.VISIBLE or View.INVISIBLE/GONE.
* @param gone Optional parameter for hiding a view. Uses View.GONE if true and View.INVISIBLE otherwise.
*/
fun View.setVisible(visible: Boolean, gone: Boolean = true) {
visibility = if (visible) {
View.VISIBLE
} else {
if (gone) {
View.GONE
} else {
View.INVISIBLE
}
}
}
/**
* Starts a marquee on some text.
* @param delay Optional parameter for changing the start delay. 3 seconds of delay by default.
*/
fun TextView.marquee(delay: Long = 3000) {
ellipsize = null
marqueeRepeatLimit = -1
isSingleLine = true
postDelayed({
ellipsize = TextUtils.TruncateAt.MARQUEE
isSelected = true
}, delay)
}
}

View File

@ -23,6 +23,22 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
window_info.render_surface = reinterpret_cast<void*>(surface);
}
void EmuWindow_Android::OnTouchPressed(int id, float x, float y) {
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchPressed(touch_x,
touch_y, id);
}
void EmuWindow_Android::OnTouchMoved(int id, float x, float y) {
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchMoved(touch_x,
touch_y, id);
}
void EmuWindow_Android::OnTouchReleased(int id) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(id);
}
void EmuWindow_Android::OnFrameDisplayed() {
if (!m_first_frame) {
Common::Android::RunJNIOnFiber<void>(

View File

@ -38,6 +38,10 @@ public:
void OnSurfaceChanged(ANativeWindow* surface);
void OnFrameDisplayed() override;
void OnTouchPressed(int id, float x, float y);
void OnTouchMoved(int id, float x, float y);
void OnTouchReleased(int id);
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override {
return {std::make_unique<GraphicsContext_Android>(m_driver_library)};
}

View File

@ -190,8 +190,7 @@ void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchPressed(JNIEnv* e
jint j_id, jfloat j_x_axis,
jfloat j_y_axis) {
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchPressed(
j_id, j_x_axis, j_y_axis);
EmulationSession::GetInstance().Window().OnTouchPressed(j_id, j_x_axis, j_y_axis);
}
}
@ -199,15 +198,14 @@ void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchMoved(JNIEnv* env
jint j_id, jfloat j_x_axis,
jfloat j_y_axis) {
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchMoved(
j_id, j_x_axis, j_y_axis);
EmulationSession::GetInstance().Window().OnTouchMoved(j_id, j_x_axis, j_y_axis);
}
}
void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchReleased(JNIEnv* env, jobject j_obj,
jint j_id) {
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(j_id);
EmulationSession::GetInstance().Window().OnTouchReleased(j_id);
}
}

View File

@ -39,10 +39,7 @@
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart"
tools:text="@string/select_gpu_driver_default" />
@ -52,10 +49,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart"
tools:text="@string/install_gpu_driver_description" />
@ -65,10 +59,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart"
tools:text="@string/install_gpu_driver_description" />

View File

@ -21,10 +21,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/button_layout"

View File

@ -40,10 +40,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="center"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="@+id/image_game_screen"

View File

@ -59,9 +59,6 @@
android:textAlignment="viewStart"
android:textSize="14sp"
android:textStyle="bold"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="none"
android:requiresFadingEdge="horizontal"
android:layout_marginTop="6dp"
android:visibility="gone"

View File

@ -76,10 +76,7 @@
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:layout_marginHorizontal="16dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="center"
tools:text="deko_basic" />

View File

@ -423,12 +423,12 @@ add_library(core STATIC
hle/service/am/applet_manager.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/display_layer_manager.cpp
hle/service/am/display_layer_manager.h
hle/service/am/hid_registration.cpp
hle/service/am/hid_registration.h
hle/service/am/library_applet_storage.cpp
hle/service/am/library_applet_storage.h
hle/service/am/managed_layer_holder.cpp
hle/service/am/managed_layer_holder.h
hle/service/am/process.cpp
hle/service/am/process.h
hle/service/am/service/all_system_applet_proxies_service.cpp
@ -481,8 +481,6 @@ add_library(core STATIC
hle/service/am/service/system_applet_proxy.h
hle/service/am/service/window_controller.cpp
hle/service/am/service/window_controller.h
hle/service/am/system_buffer_manager.cpp
hle/service/am/system_buffer_manager.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
@ -491,12 +489,12 @@ add_library(core STATIC
hle/service/apm/apm_controller.h
hle/service/apm/apm_interface.cpp
hle/service/apm/apm_interface.h
hle/service/audio/audctl.cpp
hle/service/audio/audctl.h
hle/service/audio/audin_u.cpp
hle/service/audio/audin_u.h
hle/service/audio/audio.cpp
hle/service/audio/audio.h
hle/service/audio/audio_controller.cpp
hle/service/audio/audio_controller.h
hle/service/audio/audout_u.cpp
hle/service/audio/audout_u.h
hle/service/audio/audrec_a.cpp
@ -739,15 +737,48 @@ add_library(core STATIC
hle/service/nim/nim.h
hle/service/npns/npns.cpp
hle/service/npns/npns.h
hle/service/ns/errors.h
hle/service/ns/iplatform_service_manager.cpp
hle/service/ns/iplatform_service_manager.h
hle/service/ns/account_proxy_interface.cpp
hle/service/ns/account_proxy_interface.h
hle/service/ns/application_manager_interface.cpp
hle/service/ns/application_manager_interface.h
hle/service/ns/application_version_interface.cpp
hle/service/ns/application_version_interface.h
hle/service/ns/content_management_interface.cpp
hle/service/ns/content_management_interface.h
hle/service/ns/develop_interface.cpp
hle/service/ns/develop_interface.h
hle/service/ns/document_interface.cpp
hle/service/ns/document_interface.h
hle/service/ns/download_task_interface.cpp
hle/service/ns/download_task_interface.h
hle/service/ns/dynamic_rights_interface.cpp
hle/service/ns/dynamic_rights_interface.h
hle/service/ns/ecommerce_interface.cpp
hle/service/ns/ecommerce_interface.h
hle/service/ns/factory_reset_interface.cpp
hle/service/ns/factory_reset_interface.h
hle/service/ns/language.cpp
hle/service/ns/language.h
hle/service/ns/ns_results.h
hle/service/ns/ns_types.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/pdm_qry.cpp
hle/service/ns/pdm_qry.h
hle/service/ns/platform_service_manager.cpp
hle/service/ns/platform_service_manager.h
hle/service/ns/query_service.cpp
hle/service/ns/query_service.h
hle/service/ns/read_only_application_control_data_interface.cpp
hle/service/ns/read_only_application_control_data_interface.h
hle/service/ns/read_only_application_record_interface.cpp
hle/service/ns/read_only_application_record_interface.h
hle/service/ns/service_getter_interface.cpp
hle/service/ns/service_getter_interface.h
hle/service/ns/system_update_control.cpp
hle/service/ns/system_update_control.h
hle/service/ns/system_update_interface.cpp
hle/service/ns/system_update_interface.h
hle/service/ns/vulnerability_manager_interface.cpp
hle/service/ns/vulnerability_manager_interface.h
hle/service/nvdrv/core/container.cpp
hle/service/nvdrv/core/container.h
hle/service/nvdrv/core/heap_mapper.cpp
@ -800,12 +831,12 @@ add_library(core STATIC
hle/service/nvnflinger/consumer_base.cpp
hle/service/nvnflinger/consumer_base.h
hle/service/nvnflinger/consumer_listener.h
hle/service/nvnflinger/fb_share_buffer_manager.cpp
hle/service/nvnflinger/fb_share_buffer_manager.h
hle/service/nvnflinger/graphic_buffer_producer.cpp
hle/service/nvnflinger/graphic_buffer_producer.h
hle/service/nvnflinger/hos_binder_driver_server.cpp
hle/service/nvnflinger/hos_binder_driver_server.h
hle/service/nvnflinger/hos_binder_driver.cpp
hle/service/nvnflinger/hos_binder_driver.h
hle/service/nvnflinger/hardware_composer.cpp
hle/service/nvnflinger/hardware_composer.h
hle/service/nvnflinger/hwc_layer.h
@ -815,6 +846,8 @@ add_library(core STATIC
hle/service/nvnflinger/pixel_format.h
hle/service/nvnflinger/producer_listener.h
hle/service/nvnflinger/status.h
hle/service/nvnflinger/surface_flinger.cpp
hle/service/nvnflinger/surface_flinger.h
hle/service/nvnflinger/ui/fence.h
hle/service/nvnflinger/ui/graphic_buffer.cpp
hle/service/nvnflinger/ui/graphic_buffer.h
@ -908,6 +941,8 @@ add_library(core STATIC
hle/service/server_manager.h
hle/service/service.cpp
hle/service/service.h
hle/service/services.cpp
hle/service/services.h
hle/service/set/setting_formats/appln_settings.cpp
hle/service/set/setting_formats/appln_settings.h
hle/service/set/setting_formats/device_settings.cpp
@ -955,22 +990,26 @@ add_library(core STATIC
hle/service/ssl/ssl_backend.h
hle/service/usb/usb.cpp
hle/service/usb/usb.h
hle/service/vi/display/vi_display.cpp
hle/service/vi/display/vi_display.h
hle/service/vi/layer/vi_layer.cpp
hle/service/vi/layer/vi_layer.h
hle/service/vi/application_display_service.cpp
hle/service/vi/application_display_service.h
hle/service/vi/application_root_service.cpp
hle/service/vi/application_root_service.h
hle/service/vi/hos_binder_driver.cpp
hle/service/vi/hos_binder_driver.h
hle/service/vi/conductor.cpp
hle/service/vi/conductor.h
hle/service/vi/container.cpp
hle/service/vi/container.h
hle/service/vi/display_list.h
hle/service/vi/display.h
hle/service/vi/layer_list.h
hle/service/vi/layer.h
hle/service/vi/manager_display_service.cpp
hle/service/vi/manager_display_service.h
hle/service/vi/manager_root_service.cpp
hle/service/vi/manager_root_service.h
hle/service/vi/service_creator.cpp
hle/service/vi/service_creator.h
hle/service/vi/shared_buffer_manager.cpp
hle/service/vi/shared_buffer_manager.h
hle/service/vi/system_display_service.cpp
hle/service/vi/system_display_service.h
hle/service/vi/system_root_service.cpp
@ -979,6 +1018,8 @@ add_library(core STATIC
hle/service/vi/vi_types.h
hle/service/vi/vi.cpp
hle/service/vi/vi.h
hle/service/vi/vsync_manager.cpp
hle/service/vi/vsync_manager.h
internal_network/network.cpp
internal_network/network.h
internal_network/network_interface.cpp

View File

@ -47,6 +47,7 @@
#include "core/hle/service/psc/time/system_clock.h"
#include "core/hle/service/psc/time/time_zone_service.h"
#include "core/hle/service/service.h"
#include "core/hle/service/services.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
#include "core/internal_network/network.h"
@ -310,7 +311,8 @@ struct System::Impl {
audio_core = std::make_unique<AudioCore::AudioCore>(system);
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
services = std::make_unique<Service::Services>(service_manager, system);
services =
std::make_unique<Service::Services>(service_manager, system, stop_event.get_token());
is_powered_on = true;
exit_locked = false;
@ -458,11 +460,10 @@ struct System::Impl {
gpu_core->NotifyShutdown();
}
stop_event.request_stop();
core_timing.SyncPause(false);
Network::CancelPendingSocketOperations();
kernel.SuspendEmulation(true);
if (services) {
services->KillNVNFlinger();
}
kernel.CloseServices();
kernel.ShutdownCores();
applet_manager.Reset();
@ -480,6 +481,7 @@ struct System::Impl {
cpu_manager.Shutdown();
debugger.reset();
kernel.Shutdown();
stop_event = {};
Network::RestartSocketOperations();
if (auto room_member = room_network.GetRoomMember().lock()) {
@ -615,6 +617,7 @@ struct System::Impl {
ExecuteProgramCallback execute_program_callback;
ExitCallback exit_callback;
std::stop_source stop_event;
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};

View File

@ -64,8 +64,8 @@ struct RawNACP {
u64_le cache_storage_size;
u64_le cache_storage_journal_size;
u64_le cache_storage_data_and_journal_max_size;
u64_le cache_storage_max_index;
INSERT_PADDING_BYTES(0xE70);
u16_le cache_storage_max_index;
INSERT_PADDING_BYTES(0xE76);
};
static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size.");

View File

@ -9,7 +9,7 @@
#include "core/file_sys/system_archive/data/font_standard.h"
#include "core/file_sys/system_archive/shared_font.h"
#include "core/file_sys/vfs/vfs_vector.h"
#include "core/hle/service/ns/iplatform_service_manager.h"
#include "core/hle/service/ns/platform_service_manager.h"
namespace FileSys::SystemArchive {

View File

@ -329,9 +329,8 @@ bool ProfileManager::GetProfileBaseAndData(const ProfileInfo& user, ProfileBase&
/// Returns if the system is allowing user registrations or not
bool ProfileManager::CanSystemRegisterUser() const {
return false; // TODO(ogniK): Games shouldn't have
// access to user registration, when we
// emulate qlaunch. Update this to dynamically change.
// TODO: Both games and applets can register users. Determine when this condition is not meet.
return true;
}
bool ProfileManager::RemoveUser(UUID uuid) {

View File

@ -8,13 +8,13 @@
namespace Service::AM {
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService(
"appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, nvnflinger));
server_manager->RegisterNamedService(
"appletOE", std::make_shared<IApplicationProxyService>(system, nvnflinger));
server_manager->RegisterNamedService("appletAE",
std::make_shared<IAllSystemAppletProxiesService>(system));
server_manager->RegisterNamedService("appletOE",
std::make_shared<IApplicationProxyService>(system));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -7,12 +7,8 @@ namespace Core {
class System;
}
namespace Service::Nvnflinger {
class Nvnflinger;
}
namespace Service::AM {
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
void LoopProcess(Core::System& system);
} // namespace Service::AM

View File

@ -14,10 +14,9 @@
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/am/display_layer_manager.h"
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/managed_layer_holder.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/am/system_buffer_manager.h"
namespace Service::AM {
@ -54,8 +53,7 @@ struct Applet {
HidRegistration hid_registration;
// vi state
SystemBufferManager system_buffer_manager{};
ManagedLayerHolder managed_layer_holder{};
DisplayLayerManager display_layer_manager{};
// Applet common functions
Result terminate_result{};

View File

@ -35,6 +35,21 @@ AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system,
return applet->caller_applet_broker->GetInData();
}
void PushInShowQlaunch(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments arguments{
.arguments_version = CommonArgumentVersion::Version3,
.size = CommonArgumentSize::Version3,
.library_version = 0,
.theme_color = ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
std::vector<u8> argument_data(sizeof(arguments));
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
}
void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments arguments{
.arguments_version = CommonArgumentVersion::Version3,
@ -284,6 +299,9 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters(
// Starting from frontend, some applets require input data.
switch (applet->applet_id) {
case AppletId::QLaunch:
PushInShowQlaunch(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
case AppletId::Cabinet:
PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet));
break;

View File

@ -0,0 +1,151 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/am/display_layer_manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/application_display_service.h"
#include "core/hle/service/vi/container.h"
#include "core/hle/service/vi/manager_display_service.h"
#include "core/hle/service/vi/manager_root_service.h"
#include "core/hle/service/vi/shared_buffer_manager.h"
#include "core/hle/service/vi/vi_results.h"
#include "core/hle/service/vi/vi_types.h"
namespace Service::AM {
DisplayLayerManager::DisplayLayerManager() = default;
DisplayLayerManager::~DisplayLayerManager() {
this->Finalize();
}
void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* process,
AppletId applet_id, LibraryAppletMode mode) {
R_ASSERT(system.ServiceManager()
.GetService<VI::IManagerRootService>("vi:m", true)
->GetDisplayService(&m_display_service, VI::Policy::Compositor));
R_ASSERT(m_display_service->GetManagerDisplayService(&m_manager_display_service));
m_process = process;
m_system_shared_buffer_id = 0;
m_system_shared_layer_id = 0;
m_applet_id = applet_id;
m_buffer_sharing_enabled = false;
m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
}
void DisplayLayerManager::Finalize() {
if (!m_manager_display_service) {
return;
}
// Clean up managed layers.
for (const auto& layer : m_managed_display_layers) {
m_manager_display_service->DestroyManagedLayer(layer);
}
for (const auto& layer : m_managed_display_recording_layers) {
m_manager_display_service->DestroyManagedLayer(layer);
}
// Clean up shared layers.
if (m_buffer_sharing_enabled) {
m_manager_display_service->DestroySharedLayerSession(m_process);
}
m_manager_display_service = nullptr;
m_display_service = nullptr;
}
Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
// TODO(Subv): Find out how AM determines the display to use, for now just
// create the layer in the Default display.
u64 display_id;
R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
R_TRY(m_manager_display_service->CreateManagedLayer(
out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
m_managed_display_layers.emplace(*out_layer_id);
R_SUCCEED();
}
Result DisplayLayerManager::CreateManagedDisplaySeparableLayer(u64* out_layer_id,
u64* out_recording_layer_id) {
R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
// TODO(Subv): Find out how AM determines the display to use, for now just
// create the layer in the Default display.
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
// side effects.
*out_recording_layer_id = 0;
R_RETURN(this->CreateManagedDisplayLayer(out_layer_id));
}
Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
// Succeed if already enabled.
R_SUCCEED_IF(m_buffer_sharing_enabled);
// Ensure we can access shared layers.
R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
R_UNLESS(m_applet_id != AppletId::Application, VI::ResultPermissionDenied);
// Create the shared layer.
u64 display_id;
R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
R_TRY(m_manager_display_service->CreateSharedLayerSession(m_process, &m_system_shared_buffer_id,
&m_system_shared_layer_id, display_id,
m_blending_enabled));
// We succeeded, so set up remaining state.
m_buffer_sharing_enabled = true;
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
R_SUCCEED();
}
Result DisplayLayerManager::GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
u64* out_system_shared_layer_id) {
R_TRY(this->IsSystemBufferSharingEnabled());
*out_system_shared_buffer_id = m_system_shared_buffer_id;
*out_system_shared_layer_id = m_system_shared_layer_id;
R_SUCCEED();
}
void DisplayLayerManager::SetWindowVisibility(bool visible) {
if (m_visible == visible) {
return;
}
m_visible = visible;
if (m_manager_display_service) {
if (m_system_shared_layer_id) {
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
}
for (const auto layer_id : m_managed_display_layers) {
m_manager_display_service->SetLayerVisibility(m_visible, layer_id);
}
}
}
bool DisplayLayerManager::GetWindowVisibility() const {
return m_visible;
}
Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
s32* out_fbshare_layer_index) {
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
out_was_written, out_fbshare_layer_index));
}
} // namespace Service::AM

View File

@ -0,0 +1,62 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <set>
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am_types.h"
namespace Core {
class System;
}
namespace Kernel {
class KProcess;
}
namespace Service::VI {
class IApplicationDisplayService;
class IManagerDisplayService;
} // namespace Service::VI
namespace Service::AM {
class DisplayLayerManager {
public:
explicit DisplayLayerManager();
~DisplayLayerManager();
void Initialize(Core::System& system, Kernel::KProcess* process, AppletId applet_id,
LibraryAppletMode mode);
void Finalize();
Result CreateManagedDisplayLayer(u64* out_layer_id);
Result CreateManagedDisplaySeparableLayer(u64* out_layer_id, u64* out_recording_layer_id);
Result IsSystemBufferSharingEnabled();
Result GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
u64* out_system_shared_layer_id);
void SetWindowVisibility(bool visible);
bool GetWindowVisibility() const;
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
private:
Kernel::KProcess* m_process{};
std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
std::set<u64> m_managed_display_layers{};
std::set<u64> m_managed_display_recording_layers{};
u64 m_system_shared_buffer_id{};
u64 m_system_shared_layer_id{};
AppletId m_applet_id{};
bool m_buffer_sharing_enabled{};
bool m_blending_enabled{};
bool m_visible{true};
};
} // namespace Service::AM

View File

@ -22,7 +22,7 @@
#include "core/hle/service/am/frontend/applet_web_browser.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/iplatform_service_manager.h"
#include "core/hle/service/ns/platform_service_manager.h"
#include "core/loader/loader.h"
namespace Service::AM::Frontend {

View File

@ -70,7 +70,7 @@ public:
Result Read(s64 offset, void* buffer, size_t size) override {
R_TRY(ValidateOffset(offset, size, m_size));
m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size);
m_memory.ReadBlock(m_trmem->GetSourceAddress() + offset, buffer, size);
R_SUCCEED();
}
@ -79,7 +79,7 @@ public:
R_UNLESS(m_is_writable, ResultUnknown);
R_TRY(ValidateOffset(offset, size, m_size));
m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size);
m_memory.WriteBlock(m_trmem->GetSourceAddress() + offset, buffer, size);
R_SUCCEED();
}

View File

@ -1,59 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/managed_layer_holder.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
namespace Service::AM {
ManagedLayerHolder::ManagedLayerHolder() = default;
ManagedLayerHolder::~ManagedLayerHolder() {
if (!m_nvnflinger) {
return;
}
for (const auto& layer : m_managed_display_layers) {
m_nvnflinger->DestroyLayer(layer);
}
for (const auto& layer : m_managed_display_recording_layers) {
m_nvnflinger->DestroyLayer(layer);
}
m_nvnflinger = nullptr;
}
void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
m_nvnflinger = nvnflinger;
}
void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
// TODO(Subv): Find out how AM determines the display to use, for now just
// create the layer in the Default display.
const auto display_id = m_nvnflinger->OpenDisplay("Default");
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
m_managed_display_layers.emplace(*layer_id);
*out_layer = *layer_id;
}
void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
u64* out_recording_layer) {
// TODO(Subv): Find out how AM determines the display to use, for now just
// create the layer in the Default display.
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
// side effects.
// TODO: Support multiple layers
const auto display_id = m_nvnflinger->OpenDisplay("Default");
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
m_managed_display_layers.emplace(*layer_id);
*out_layer = *layer_id;
*out_recording_layer = 0;
}
} // namespace Service::AM

View File

@ -1,32 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <set>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Service::Nvnflinger {
class Nvnflinger;
}
namespace Service::AM {
class ManagedLayerHolder {
public:
ManagedLayerHolder();
~ManagedLayerHolder();
void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
void CreateManagedDisplayLayer(u64* out_layer);
void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
private:
Nvnflinger::Nvnflinger* m_nvnflinger{};
std::set<u64> m_managed_display_layers{};
std::set<u64> m_managed_display_recording_layers{};
};
} // namespace Service::AM

View File

@ -10,9 +10,8 @@
namespace Service::AM {
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "appletAE"}, m_nvnflinger{nvnflinger} {
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_)
: ServiceFramework{system_, "appletAE"} {
// clang-format off
static const FunctionInfo functions[] = {
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
@ -37,8 +36,8 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
*out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
system, applet, process_handle.Get(), m_nvnflinger);
*out_system_applet_proxy =
std::make_shared<ISystemAppletProxy>(system, applet, process_handle.Get());
R_SUCCEED();
} else {
UNIMPLEMENTED();
@ -53,8 +52,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
*out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
system, applet, process_handle.Get(), m_nvnflinger);
*out_library_applet_proxy =
std::make_shared<ILibraryAppletProxy>(system, applet, process_handle.Get());
R_SUCCEED();
} else {
UNIMPLEMENTED();

View File

@ -8,10 +8,6 @@
namespace Service {
namespace Nvnflinger {
class Nvnflinger;
}
namespace AM {
struct Applet;
@ -22,8 +18,7 @@ class ISystemAppletProxy;
class IAllSystemAppletProxiesService final
: public ServiceFramework<IAllSystemAppletProxiesService> {
public:
explicit IAllSystemAppletProxiesService(Core::System& system_,
Nvnflinger::Nvnflinger& nvnflinger);
explicit IAllSystemAppletProxiesService(Core::System& system_);
~IAllSystemAppletProxiesService() override;
private:
@ -40,7 +35,6 @@ private:
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
Nvnflinger::Nvnflinger& m_nvnflinger;
};
} // namespace AM

View File

@ -15,7 +15,9 @@
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/save_data_controller.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/ns/application_manager_interface.h"
#include "core/hle/service/ns/service_getter_interface.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM {
@ -40,7 +42,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
{26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"},
{27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"},
{28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"},
{29, nullptr, "GetCacheStorageMax"},
{29, D<&IApplicationFunctions::GetCacheStorageMax>, "GetCacheStorageMax"},
{30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"},
{31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"},
{32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"},
@ -162,11 +164,13 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
// Call IApplicationManagerInterface implementation.
auto& service_manager = system.ServiceManager();
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2");
std::shared_ptr<NS::IApplicationManagerInterface> app_man;
R_TRY(ns_am2->GetApplicationManagerInterface(&app_man));
// Get desired application language
u8 desired_language{};
NS::ApplicationLanguage desired_language{};
R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
// Convert to settings language code.
@ -267,6 +271,22 @@ Result IApplicationFunctions::GetSaveDataSizeMax(Out<u64> out_max_normal_size,
R_SUCCEED();
}
Result IApplicationFunctions::GetCacheStorageMax(Out<u32> out_cache_storage_index_max,
Out<u64> out_max_journal_size) {
LOG_DEBUG(Service_AM, "called");
std::vector<u8> nacp;
R_TRY(system.GetARPManager().GetControlProperty(&nacp, m_applet->program_id));
auto raw_nacp = std::make_unique<FileSys::RawNACP>();
std::memcpy(raw_nacp.get(), nacp.data(), std::min(sizeof(*raw_nacp), nacp.size()));
*out_cache_storage_index_max = static_cast<u32>(raw_nacp->cache_storage_max_index);
*out_max_journal_size = static_cast<u64>(raw_nacp->cache_storage_data_and_journal_max_size);
R_SUCCEED();
}
Result IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(s64 unused) {
LOG_WARNING(Service_AM, "(STUBBED) called");

View File

@ -40,6 +40,7 @@ private:
Result CreateCacheStorage(Out<u32> out_target_media, Out<u64> out_required_size, u16 index,
u64 normal_size, u64 journal_size);
Result GetSaveDataSizeMax(Out<u64> out_max_normal_size, Out<u64> out_max_journal_size);
Result GetCacheStorageMax(Out<u32> out_cache_storage_index_max, Out<u64> out_max_journal_size);
Result BeginBlockingHomeButtonShortAndLongPressed(s64 unused);
Result EndBlockingHomeButtonShortAndLongPressed();
Result BeginBlockingHomeButton(s64 timeout_ns);

View File

@ -17,9 +17,9 @@
namespace Service::AM {
IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "IApplicationProxy"},
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
Kernel::KProcess* process)
: ServiceFramework{system_, "IApplicationProxy"}, m_process{process}, m_applet{
std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@ -77,8 +77,7 @@ Result IApplicationProxy::GetWindowController(
Result IApplicationProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
LOG_DEBUG(Service_AM, "called");
*out_self_controller =
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
R_SUCCEED();
}

View File

@ -22,7 +22,7 @@ class IWindowController;
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
Kernel::KProcess* process);
~IApplicationProxy();
private:
@ -40,7 +40,6 @@ private:
Out<SharedPointer<IApplicationFunctions>> out_application_functions);
private:
Nvnflinger::Nvnflinger& m_nvnflinger;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -10,9 +10,8 @@
namespace Service::AM {
IApplicationProxyService::IApplicationProxyService(Core::System& system_,
Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "appletOE"}, m_nvnflinger{nvnflinger} {
IApplicationProxyService::IApplicationProxyService(Core::System& system_)
: ServiceFramework{system_, "appletOE"} {
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
};
@ -28,7 +27,7 @@ Result IApplicationProxyService::OpenApplicationProxy(
if (const auto applet = this->GetAppletFromProcessId(pid)) {
*out_application_proxy =
std::make_shared<IApplicationProxy>(system, applet, process_handle.Get(), m_nvnflinger);
std::make_shared<IApplicationProxy>(system, applet, process_handle.Get());
R_SUCCEED();
} else {
UNIMPLEMENTED();

View File

@ -8,10 +8,6 @@
namespace Service {
namespace Nvnflinger {
class Nvnflinger;
}
namespace AM {
struct Applet;
@ -19,7 +15,7 @@ class IApplicationProxy;
class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
public:
explicit IApplicationProxyService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger);
explicit IApplicationProxyService(Core::System& system_);
~IApplicationProxyService() override;
private:
@ -28,7 +24,6 @@ private:
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
Nvnflinger::Nvnflinger& m_nvnflinger;
};
} // namespace AM

View File

@ -69,7 +69,7 @@ Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_i
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
@ -81,7 +81,7 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
@ -93,7 +93,7 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}

View File

@ -135,7 +135,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
case LibraryAppletMode::AllForegroundInitiallyHidden:
applet->hid_registration.EnableAppletToGetInput(false);
applet->focus_state = FocusState::NotInFocus;
applet->system_buffer_manager.SetWindowVisibility(false);
applet->display_layer_manager.SetWindowVisibility(false);
applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
break;
}

View File

@ -19,10 +19,9 @@
namespace Service::AM {
ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process,
Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "ILibraryAppletProxy"},
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
Kernel::KProcess* process)
: ServiceFramework{system_, "ILibraryAppletProxy"}, m_process{process}, m_applet{
std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@ -83,8 +82,7 @@ Result ILibraryAppletProxy::GetWindowController(
Result ILibraryAppletProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
LOG_DEBUG(Service_AM, "called");
*out_self_controller =
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
R_SUCCEED();
}

View File

@ -25,7 +25,7 @@ class IWindowController;
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
Kernel::KProcess* process);
~ILibraryAppletProxy();
private:
@ -47,7 +47,6 @@ private:
Result GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
Nvnflinger::Nvnflinger& m_nvnflinger;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -14,7 +14,8 @@
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/application_manager_interface.h"
#include "core/hle/service/ns/service_getter_interface.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM {
@ -256,11 +257,13 @@ Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(
// Call IApplicationManagerInterface implementation.
auto& service_manager = system.ServiceManager();
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2");
std::shared_ptr<NS::IApplicationManagerInterface> app_man;
R_TRY(ns_am2->GetApplicationManagerInterface(&app_man));
// Get desired application language
u8 desired_language{};
NS::ApplicationLanguage desired_language{};
R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
// Convert to settings language code.
@ -284,17 +287,17 @@ Result ILibraryAppletSelfAccessor::GetCurrentApplicationId(Out<u64> out_applicat
}
Result ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(
Out<bool> out_no_users_available, Out<s32> out_users_count,
Out<bool> out_can_select_any_user, Out<s32> out_users_count,
OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users) {
const Service::Account::ProfileManager manager{};
*out_no_users_available = true;
*out_can_select_any_user = false;
*out_users_count = -1;
LOG_INFO(Service_AM, "called");
if (manager.GetUserCount() > 0) {
*out_no_users_available = false;
*out_can_select_any_user = true;
*out_users_count = static_cast<s32>(manager.GetUserCount());
const auto users = manager.GetAllUsers();

View File

@ -71,7 +71,7 @@ private:
ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context);
Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language);
Result GetCurrentApplicationId(Out<u64> out_application_id);
Result GetMainAppletAvailableUsers(Out<bool> out_no_users_available, Out<s32> out_users_count,
Result GetMainAppletAvailableUsers(Out<bool> out_can_select_any_user, Out<s32> out_users_count,
OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users);
Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually);
Result Cmd160(Out<u64> out_unknown0);

View File

@ -15,9 +15,9 @@
namespace Service::AM {
ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "ISelfController"},
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
Kernel::KProcess* process)
: ServiceFramework{system_, "ISelfController"}, m_process{process}, m_applet{
std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ISelfController::Exit>, "Exit"},
@ -72,9 +72,16 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
// clang-format on
RegisterHandlers(functions);
std::scoped_lock lk{m_applet->lock};
m_applet->display_layer_manager.Initialize(system, m_process, m_applet->applet_id,
m_applet->library_applet_mode);
}
ISelfController::~ISelfController() = default;
ISelfController::~ISelfController() {
std::scoped_lock lk{m_applet->lock};
m_applet->display_layer_manager.Finalize();
}
Result ISelfController::Exit() {
LOG_DEBUG(Service_AM, "called");
@ -212,48 +219,42 @@ Result ISelfController::SetAlbumImageOrientation(
Result ISelfController::IsSystemBufferSharingEnabled() {
LOG_INFO(Service_AM, "called");
R_SUCCEED_IF(m_applet->system_buffer_manager.Initialize(
&m_nvnflinger, m_process, m_applet->applet_id, m_applet->library_applet_mode));
R_THROW(VI::ResultOperationFailed);
std::scoped_lock lk{m_applet->lock};
R_RETURN(m_applet->display_layer_manager.IsSystemBufferSharingEnabled());
}
Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_TRY(this->IsSystemBufferSharingEnabled());
LOG_INFO(Service_AM, "called");
u64 layer_id;
m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id);
R_SUCCEED();
std::scoped_lock lk{m_applet->lock};
R_RETURN(m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id));
}
Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) {
LOG_INFO(Service_AM, "(STUBBED) called");
LOG_INFO(Service_AM, "called");
R_TRY(this->IsSystemBufferSharingEnabled());
m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id);
R_SUCCEED();
std::scoped_lock lk{m_applet->lock};
R_RETURN(
m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id));
}
Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) {
LOG_INFO(Service_AM, "called");
m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
m_applet->managed_layer_holder.CreateManagedDisplayLayer(out_layer_id);
R_SUCCEED();
std::scoped_lock lk{m_applet->lock};
R_RETURN(m_applet->display_layer_manager.CreateManagedDisplayLayer(out_layer_id));
}
Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id,
Out<u64> out_recording_layer_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
m_applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(out_layer_id,
out_recording_layer_id);
R_SUCCEED();
std::scoped_lock lk{m_applet->lock};
R_RETURN(m_applet->display_layer_manager.CreateManagedDisplaySeparableLayer(
out_layer_id, out_recording_layer_id));
}
Result ISelfController::SetHandlesRequestToDisplay(bool enable) {

View File

@ -23,7 +23,7 @@ struct Applet;
class ISelfController final : public ServiceFramework<ISelfController> {
public:
explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
Kernel::KProcess* process);
~ISelfController() override;
private:
@ -64,7 +64,6 @@ private:
Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
Result SetRecordVolumeMuted(bool muted);
Nvnflinger::Nvnflinger& m_nvnflinger;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -19,10 +19,9 @@
namespace Service::AM {
ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process,
Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "ISystemAppletProxy"},
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
Kernel::KProcess* process)
: ServiceFramework{system_, "ISystemAppletProxy"}, m_process{process}, m_applet{
std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@ -83,8 +82,7 @@ Result ISystemAppletProxy::GetWindowController(
Result ISystemAppletProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
LOG_DEBUG(Service_AM, "called");
*out_self_controller =
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
R_SUCCEED();
}

View File

@ -25,7 +25,7 @@ class IWindowController;
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
Kernel::KProcess* process);
~ISystemAppletProxy();
private:
@ -46,7 +46,6 @@ private:
Result GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
Nvnflinger::Nvnflinger& m_nvnflinger;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -63,7 +63,7 @@ Result IWindowController::RejectToChangeIntoBackground() {
}
Result IWindowController::SetAppletWindowVisibility(bool visible) {
m_applet->system_buffer_manager.SetWindowVisibility(visible);
m_applet->display_layer_manager.SetWindowVisibility(visible);
m_applet->hid_registration.EnableAppletToGetInput(visible);
if (visible) {

View File

@ -1,80 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/system_buffer_manager.h"
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/vi/vi_results.h"
namespace Service::AM {
SystemBufferManager::SystemBufferManager() = default;
SystemBufferManager::~SystemBufferManager() {
if (!m_nvnflinger) {
return;
}
// Clean up shared layers.
if (m_buffer_sharing_enabled) {
m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
}
}
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
AppletId applet_id, LibraryAppletMode mode) {
if (m_nvnflinger) {
return m_buffer_sharing_enabled;
}
m_process = process;
m_nvnflinger = nvnflinger;
m_buffer_sharing_enabled = false;
m_system_shared_buffer_id = 0;
m_system_shared_layer_id = 0;
if (applet_id <= AppletId::Application) {
return false;
}
Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
if (mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay) {
blending = Nvnflinger::LayerBlending::Coverage;
}
const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending);
if (res.IsSuccess()) {
m_buffer_sharing_enabled = true;
m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
}
return m_buffer_sharing_enabled;
}
void SystemBufferManager::SetWindowVisibility(bool visible) {
if (m_visible == visible) {
return;
}
m_visible = visible;
if (m_nvnflinger) {
m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
}
}
Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
s32* out_fbshare_layer_index) {
if (!m_buffer_sharing_enabled) {
return VI::ResultPermissionDenied;
}
return m_nvnflinger->GetSystemBufferManager().WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index);
}
} // namespace Service::AM

View File

@ -1,52 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <set>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/service/am/am_types.h"
namespace Kernel {
class KProcess;
}
namespace Service::Nvnflinger {
class Nvnflinger;
}
union Result;
namespace Service::AM {
class SystemBufferManager {
public:
SystemBufferManager();
~SystemBufferManager();
bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id,
LibraryAppletMode mode);
void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
u64* out_system_shared_layer_id) {
*out_system_shared_buffer_id = m_system_shared_buffer_id;
*out_system_shared_layer_id = m_system_shared_layer_id;
}
void SetWindowVisibility(bool visible);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
private:
Kernel::KProcess* m_process{};
Nvnflinger::Nvnflinger* m_nvnflinger{};
bool m_buffer_sharing_enabled{};
bool m_visible{true};
u64 m_system_shared_buffer_id{};
u64 m_system_shared_layer_id{};
};
} // namespace Service::AM

View File

@ -1,201 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/audio/audctl.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
namespace Service::Audio {
AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetTargetVolume"},
{1, nullptr, "SetTargetVolume"},
{2, &AudCtl::GetTargetVolumeMin, "GetTargetVolumeMin"},
{3, &AudCtl::GetTargetVolumeMax, "GetTargetVolumeMax"},
{4, nullptr, "IsTargetMute"},
{5, nullptr, "SetTargetMute"},
{6, nullptr, "IsTargetConnected"},
{7, nullptr, "SetDefaultTarget"},
{8, nullptr, "GetDefaultTarget"},
{9, &AudCtl::GetAudioOutputMode, "GetAudioOutputMode"},
{10, &AudCtl::SetAudioOutputMode, "SetAudioOutputMode"},
{11, nullptr, "SetForceMutePolicy"},
{12, &AudCtl::GetForceMutePolicy, "GetForceMutePolicy"},
{13, &AudCtl::GetOutputModeSetting, "GetOutputModeSetting"},
{14, &AudCtl::SetOutputModeSetting, "SetOutputModeSetting"},
{15, nullptr, "SetOutputTarget"},
{16, nullptr, "SetInputTargetForceEnabled"},
{17, &AudCtl::SetHeadphoneOutputLevelMode, "SetHeadphoneOutputLevelMode"},
{18, &AudCtl::GetHeadphoneOutputLevelMode, "GetHeadphoneOutputLevelMode"},
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
{22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
{23, nullptr, "SetSystemOutputMasterVolume"},
{24, nullptr, "GetSystemOutputMasterVolume"},
{25, nullptr, "GetAudioVolumeDataForPlayReport"},
{26, nullptr, "UpdateHeadphoneSettings"},
{27, nullptr, "SetVolumeMappingTableForDev"},
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{30, &AudCtl::SetSpeakerAutoMuteEnabled, "SetSpeakerAutoMuteEnabled"},
{31, &AudCtl::IsSpeakerAutoMuteEnabled, "IsSpeakerAutoMuteEnabled"},
{32, nullptr, "GetActiveOutputTarget"},
{33, nullptr, "GetTargetDeviceInfo"},
{34, nullptr, "AcquireTargetNotification"},
{35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{37, nullptr, "SetHearingProtectionSafeguardEnabled"},
{38, nullptr, "IsHearingProtectionSafeguardEnabled"},
{39, nullptr, "IsHearingProtectionSafeguardMonitoringOutputForDebug"},
{40, nullptr, "GetSystemInformationForDebug"},
{41, nullptr, "SetVolumeButtonLongPressTime"},
{42, nullptr, "SetNativeVolumeForDebug"},
{10000, nullptr, "NotifyAudioOutputTargetForPlayReport"},
{10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"},
{10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"},
{10100, nullptr, "GetAudioVolumeDataForPlayReport"},
{10101, nullptr, "BindAudioVolumeUpdateEventForPlayReport"},
{10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"},
{10103, nullptr, "GetAudioOutputTargetForPlayReport"},
{10104, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"},
{50000, nullptr, "SetAnalogInputBoostGainForPrototyping"},
};
// clang-format on
RegisterHandlers(functions);
m_set_sys =
system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
}
AudCtl::~AudCtl() = default;
void AudCtl::GetTargetVolumeMin(HLERequestContext& ctx) {
LOG_DEBUG(Audio, "called.");
// This service function is currently hardcoded on the
// actual console to this value (as of 8.0.0).
constexpr s32 target_min_volume = 0;
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(target_min_volume);
}
void AudCtl::GetTargetVolumeMax(HLERequestContext& ctx) {
LOG_DEBUG(Audio, "called.");
// This service function is currently hardcoded on the
// actual console to this value (as of 8.0.0).
constexpr s32 target_max_volume = 15;
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(target_max_volume);
}
void AudCtl::GetAudioOutputMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()};
Set::AudioOutputMode output_mode{};
const auto result = m_set_sys->GetAudioOutputMode(&output_mode, target);
LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.PushEnum(output_mode);
}
void AudCtl::SetAudioOutputMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()};
const auto output_mode{rp.PopEnum<Set::AudioOutputMode>()};
const auto result = m_set_sys->SetAudioOutputMode(target, output_mode);
LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void AudCtl::GetForceMutePolicy(HLERequestContext& ctx) {
LOG_WARNING(Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(ForceMutePolicy::Disable);
}
void AudCtl::GetOutputModeSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()};
LOG_WARNING(Audio, "(STUBBED) called, target={}", target);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(Set::AudioOutputMode::ch_7_1);
}
void AudCtl::SetOutputModeSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()};
const auto output_mode{rp.PopEnum<Set::AudioOutputMode>()};
LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AudCtl::SetHeadphoneOutputLevelMode(HLERequestContext& ctx) {
LOG_WARNING(Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AudCtl::GetHeadphoneOutputLevelMode(HLERequestContext& ctx) {
LOG_WARNING(Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(HeadphoneOutputLevelMode::Normal);
}
void AudCtl::SetSpeakerAutoMuteEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto is_speaker_auto_mute_enabled{rp.Pop<bool>()};
LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}",
is_speaker_auto_mute_enabled);
const auto result = m_set_sys->SetSpeakerAutoMuteFlag(is_speaker_auto_mute_enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void AudCtl::IsSpeakerAutoMuteEnabled(HLERequestContext& ctx) {
bool is_speaker_auto_mute_enabled{};
const auto result = m_set_sys->GetSpeakerAutoMuteFlag(&is_speaker_auto_mute_enabled);
LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}",
is_speaker_auto_mute_enabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push<u8>(is_speaker_auto_mute_enabled);
}
} // namespace Service::Audio

View File

@ -1,50 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::Set {
class ISystemSettingsServer;
}
namespace Service::Audio {
class AudCtl final : public ServiceFramework<AudCtl> {
public:
explicit AudCtl(Core::System& system_);
~AudCtl() override;
private:
enum class ForceMutePolicy {
Disable,
SpeakerMuteOnHeadphoneUnplugged,
};
enum class HeadphoneOutputLevelMode {
Normal,
HighPower,
};
void GetTargetVolumeMin(HLERequestContext& ctx);
void GetTargetVolumeMax(HLERequestContext& ctx);
void GetAudioOutputMode(HLERequestContext& ctx);
void SetAudioOutputMode(HLERequestContext& ctx);
void GetForceMutePolicy(HLERequestContext& ctx);
void GetOutputModeSetting(HLERequestContext& ctx);
void SetOutputModeSetting(HLERequestContext& ctx);
void SetHeadphoneOutputLevelMode(HLERequestContext& ctx);
void GetHeadphoneOutputLevelMode(HLERequestContext& ctx);
void SetSpeakerAutoMuteEnabled(HLERequestContext& ctx);
void IsSpeakerAutoMuteEnabled(HLERequestContext& ctx);
void AcquireTargetNotification(HLERequestContext& ctx);
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
};
} // namespace Service::Audio

View File

@ -2,9 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/audio/audctl.h"
#include "core/hle/service/audio/audin_u.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/audio/audio_controller.h"
#include "core/hle/service/audio/audout_u.h"
#include "core/hle/service/audio/audrec_a.h"
#include "core/hle/service/audio/audrec_u.h"
@ -18,7 +18,7 @@ namespace Service::Audio {
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("audctl", std::make_shared<AudCtl>(system));
server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system));
server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system));
server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system));

View File

@ -0,0 +1,174 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/audio/audio_controller.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
namespace Service::Audio {
IAudioController::IAudioController(Core::System& system_)
: ServiceFramework{system_, "audctl"}, service_context{system, "audctl"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetTargetVolume"},
{1, nullptr, "SetTargetVolume"},
{2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
{3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
{4, nullptr, "IsTargetMute"},
{5, nullptr, "SetTargetMute"},
{6, nullptr, "IsTargetConnected"},
{7, nullptr, "SetDefaultTarget"},
{8, nullptr, "GetDefaultTarget"},
{9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
{10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
{11, nullptr, "SetForceMutePolicy"},
{12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
{13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
{14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
{15, nullptr, "SetOutputTarget"},
{16, nullptr, "SetInputTargetForceEnabled"},
{17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
{18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
{22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
{23, nullptr, "SetSystemOutputMasterVolume"},
{24, nullptr, "GetSystemOutputMasterVolume"},
{25, nullptr, "GetAudioVolumeDataForPlayReport"},
{26, nullptr, "UpdateHeadphoneSettings"},
{27, nullptr, "SetVolumeMappingTableForDev"},
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
{31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
{32, nullptr, "GetActiveOutputTarget"},
{33, nullptr, "GetTargetDeviceInfo"},
{34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
{35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{37, nullptr, "SetHearingProtectionSafeguardEnabled"},
{38, nullptr, "IsHearingProtectionSafeguardEnabled"},
{39, nullptr, "IsHearingProtectionSafeguardMonitoringOutputForDebug"},
{40, nullptr, "GetSystemInformationForDebug"},
{41, nullptr, "SetVolumeButtonLongPressTime"},
{42, nullptr, "SetNativeVolumeForDebug"},
{10000, nullptr, "NotifyAudioOutputTargetForPlayReport"},
{10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"},
{10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"},
{10100, nullptr, "GetAudioVolumeDataForPlayReport"},
{10101, nullptr, "BindAudioVolumeUpdateEventForPlayReport"},
{10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"},
{10103, nullptr, "GetAudioOutputTargetForPlayReport"},
{10104, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"},
{50000, nullptr, "SetAnalogInputBoostGainForPrototyping"},
};
// clang-format on
RegisterHandlers(functions);
m_set_sys =
system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
notification_event = service_context.CreateEvent("IAudioController:NotificationEvent");
}
IAudioController::~IAudioController() {
service_context.CloseEvent(notification_event);
};
Result IAudioController::GetTargetVolumeMin(Out<s32> out_target_min_volume) {
LOG_DEBUG(Audio, "called.");
// This service function is currently hardcoded on the
// actual console to this value (as of 8.0.0).
*out_target_min_volume = 0;
R_SUCCEED();
}
Result IAudioController::GetTargetVolumeMax(Out<s32> out_target_max_volume) {
LOG_DEBUG(Audio, "called.");
// This service function is currently hardcoded on the
// actual console to this value (as of 8.0.0).
*out_target_max_volume = 15;
R_SUCCEED();
}
Result IAudioController::GetAudioOutputMode(Out<Set::AudioOutputMode> out_output_mode,
Set::AudioOutputModeTarget target) {
const auto result = m_set_sys->GetAudioOutputMode(out_output_mode, target);
LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, *out_output_mode);
R_RETURN(result);
}
Result IAudioController::SetAudioOutputMode(Set::AudioOutputModeTarget target,
Set::AudioOutputMode output_mode) {
LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
R_RETURN(m_set_sys->SetAudioOutputMode(target, output_mode));
}
Result IAudioController::GetForceMutePolicy(Out<ForceMutePolicy> out_mute_policy) {
LOG_WARNING(Audio, "(STUBBED) called");
// Removed on FW 13.2.1+
*out_mute_policy = ForceMutePolicy::Disable;
R_SUCCEED();
}
Result IAudioController::GetOutputModeSetting(Out<Set::AudioOutputMode> out_output_mode,
Set::AudioOutputModeTarget target) {
LOG_WARNING(Audio, "(STUBBED) called, target={}", target);
*out_output_mode = Set::AudioOutputMode::ch_7_1;
R_SUCCEED();
}
Result IAudioController::SetOutputModeSetting(Set::AudioOutputModeTarget target,
Set::AudioOutputMode output_mode) {
LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
R_SUCCEED();
}
Result IAudioController::SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode) {
LOG_WARNING(Audio, "(STUBBED) called");
R_SUCCEED();
}
Result IAudioController::GetHeadphoneOutputLevelMode(
Out<HeadphoneOutputLevelMode> out_output_level_mode) {
LOG_INFO(Audio, "called");
*out_output_level_mode = HeadphoneOutputLevelMode::Normal;
R_SUCCEED();
}
Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
R_RETURN(m_set_sys->SetSpeakerAutoMuteFlag(is_speaker_auto_mute_enabled));
}
Result IAudioController::IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled) {
const auto result = m_set_sys->GetSpeakerAutoMuteFlag(out_is_speaker_auto_mute_enabled);
LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", *out_is_speaker_auto_mute_enabled);
R_RETURN(result);
}
Result IAudioController::AcquireTargetNotification(
OutCopyHandle<Kernel::KReadableEvent> out_notification_event) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_notification_event = &notification_event->GetReadableEvent();
R_SUCCEED();
}
} // namespace Service::Audio

View File

@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/settings_types.h"
namespace Core {
class System;
}
namespace Service::Set {
class ISystemSettingsServer;
}
namespace Service::Audio {
class IAudioController final : public ServiceFramework<IAudioController> {
public:
explicit IAudioController(Core::System& system_);
~IAudioController() override;
private:
enum class ForceMutePolicy {
Disable,
SpeakerMuteOnHeadphoneUnplugged,
};
enum class HeadphoneOutputLevelMode {
Normal,
HighPower,
};
Result GetTargetVolumeMin(Out<s32> out_target_min_volume);
Result GetTargetVolumeMax(Out<s32> out_target_max_volume);
Result GetAudioOutputMode(Out<Set::AudioOutputMode> out_output_mode,
Set::AudioOutputModeTarget target);
Result SetAudioOutputMode(Set::AudioOutputModeTarget target, Set::AudioOutputMode output_mode);
Result GetForceMutePolicy(Out<ForceMutePolicy> out_mute_policy);
Result GetOutputModeSetting(Out<Set::AudioOutputMode> out_output_mode,
Set::AudioOutputModeTarget target);
Result SetOutputModeSetting(Set::AudioOutputModeTarget target,
Set::AudioOutputMode output_mode);
Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event);
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* notification_event;
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
};
} // namespace Service::Audio

View File

@ -16,7 +16,7 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetAlbumFileCount"},
{1, nullptr, "GetAlbumFileList"},
{1, C<&IAlbumAccessorService::GetAlbumFileList>, "GetAlbumFileList"},
{2, nullptr, "LoadAlbumFile"},
{3, C<&IAlbumAccessorService::DeleteAlbumFile>, "DeleteAlbumFile"},
{4, nullptr, "StorageCopyAlbumFile"},
@ -62,6 +62,15 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
IAlbumAccessorService::~IAlbumAccessorService() = default;
Result IAlbumAccessorService::GetAlbumFileList(
Out<u64> out_count, AlbumStorage storage,
OutArray<AlbumEntry, BufferAttr_HipcMapAlias> out_entries) {
LOG_INFO(Service_Capture, "called, storage={}", storage);
const Result result = manager->GetAlbumFileList(out_entries, *out_count, storage, 0);
R_RETURN(TranslateResult(result));
}
Result IAlbumAccessorService::DeleteAlbumFile(AlbumFileId file_id) {
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}",
file_id.application_id, file_id.storage, file_id.type);

View File

@ -21,6 +21,9 @@ public:
~IAlbumAccessorService() override;
private:
Result GetAlbumFileList(Out<u64> out_count, AlbumStorage storage,
OutArray<AlbumEntry, BufferAttr_HipcMapAlias> out_entries);
Result DeleteAlbumFile(AlbumFileId file_id);
Result IsAlbumMounted(Out<bool> out_is_mounted, AlbumStorage storage);

View File

@ -3,6 +3,8 @@
#include <memory>
#include "common/logging/log.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/erpt/erpt.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
@ -15,7 +17,7 @@ public:
explicit ErrorReportContext(Core::System& system_) : ServiceFramework{system_, "erpt:c"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SubmitContext"},
{0, C<&ErrorReportContext::SubmitContext>, "SubmitContext"},
{1, nullptr, "CreateReportV0"},
{2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
{3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
@ -36,6 +38,14 @@ public:
RegisterHandlers(functions);
}
private:
Result SubmitContext(InBuffer<BufferAttr_HipcMapAlias> buffer_a,
InBuffer<BufferAttr_HipcMapAlias> buffer_b) {
LOG_WARNING(Service_SET, "(STUBBED) called, buffer_a_size={}, buffer_b_size={}",
buffer_a.size(), buffer_b.size());
R_SUCCEED();
}
};
class ErrorReportSession final : public ServiceFramework<ErrorReportSession> {

View File

@ -336,7 +336,7 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{1012, nullptr, "GetFsStackUsage"},
{1013, nullptr, "UnsetSaveDataRootPath"},
{1014, nullptr, "OutputMultiProgramTagAccessLog"},
{1016, nullptr, "FlushAccessLogOnSdCard"},
{1016, &FSP_SRV::FlushAccessLogOnSdCard, "FlushAccessLogOnSdCard"},
{1017, nullptr, "OutputApplicationInfoAccessLog"},
{1018, nullptr, "SetDebugOption"},
{1019, nullptr, "UnsetDebugOption"},
@ -706,6 +706,13 @@ void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) {
rb.Push(access_log_program_index);
}
void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto index{rp.Pop<s32>()};

View File

@ -58,6 +58,7 @@ private:
void SetGlobalAccessLogMode(HLERequestContext& ctx);
void GetGlobalAccessLogMode(HLERequestContext& ctx);
void OutputAccessLogToSdCard(HLERequestContext& ctx);
void FlushAccessLogOnSdCard(HLERequestContext& ctx);
void GetProgramIndexForAccessLog(HLERequestContext& ctx);
void OpenMultiCommitManager(HLERequestContext& ctx);
void GetCacheStorageSize(HLERequestContext& ctx);

View File

@ -186,6 +186,10 @@ TimeManager::TimeManager(Core::System& system)
}
}
TimeManager::~TimeManager() {
ResetTimeZoneBinary();
}
Result TimeManager::SetupStandardSteadyClockCore() {
Common::UUID external_clock_source_id{};
auto res = m_set_sys->GetExternalSteadyClockSourceId(&external_clock_source_id);

View File

@ -26,6 +26,7 @@ namespace Service::Glue::Time {
class TimeManager {
public:
explicit TimeManager(Core::System& system);
~TimeManager();
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/ns/account_proxy_interface.h"
namespace Service::NS {
IAccountProxyInterface::IAccountProxyInterface(Core::System& system_)
: ServiceFramework{system_, "IAccountProxyInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateUserAccount"},
};
// clang-format on
RegisterHandlers(functions);
}
IAccountProxyInterface::~IAccountProxyInterface() = default;
} // namespace Service::NS

View File

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::NS {
class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
public:
explicit IAccountProxyInterface(Core::System& system_);
~IAccountProxyInterface() override;
};
} // namespace Service::NS

View File

@ -0,0 +1,518 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/application_manager_interface.h"
#include "core/hle/service/ns/content_management_interface.h"
#include "core/hle/service/ns/read_only_application_control_data_interface.h"
namespace Service::NS {
IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_)
: ServiceFramework{system_, "IApplicationManagerInterface"},
service_context{system, "IApplicationManagerInterface"},
record_update_system_event{service_context}, sd_card_mount_status_event{service_context},
gamecard_update_detection_event{service_context},
gamecard_mount_status_event{service_context}, gamecard_mount_failure_event{service_context} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationManagerInterface::ListApplicationRecord>, "ListApplicationRecord"},
{1, nullptr, "GenerateApplicationRecordCount"},
{2, D<&IApplicationManagerInterface::GetApplicationRecordUpdateSystemEvent>, "GetApplicationRecordUpdateSystemEvent"},
{3, nullptr, "GetApplicationViewDeprecated"},
{4, nullptr, "DeleteApplicationEntity"},
{5, nullptr, "DeleteApplicationCompletely"},
{6, nullptr, "IsAnyApplicationEntityRedundant"},
{7, nullptr, "DeleteRedundantApplicationEntity"},
{8, nullptr, "IsApplicationEntityMovable"},
{9, nullptr, "MoveApplicationEntity"},
{11, nullptr, "CalculateApplicationOccupiedSize"},
{16, nullptr, "PushApplicationRecord"},
{17, nullptr, "ListApplicationRecordContentMeta"},
{19, nullptr, "LaunchApplicationOld"},
{21, nullptr, "GetApplicationContentPath"},
{22, nullptr, "TerminateApplication"},
{23, nullptr, "ResolveApplicationContentPath"},
{26, nullptr, "BeginInstallApplication"},
{27, nullptr, "DeleteApplicationRecord"},
{30, nullptr, "RequestApplicationUpdateInfo"},
{31, nullptr, "Unknown31"},
{32, nullptr, "CancelApplicationDownload"},
{33, nullptr, "ResumeApplicationDownload"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{38, D<&IApplicationManagerInterface::CheckApplicationLaunchVersion>, "CheckApplicationLaunchVersion"},
{39, nullptr, "CheckApplicationLaunchRights"},
{40, nullptr, "GetApplicationLogoData"},
{41, nullptr, "CalculateApplicationDownloadRequiredSize"},
{42, nullptr, "CleanupSdCard"},
{43, D<&IApplicationManagerInterface::CheckSdCardMountStatus>, "CheckSdCardMountStatus"},
{44, D<&IApplicationManagerInterface::GetSdCardMountStatusChangedEvent>, "GetSdCardMountStatusChangedEvent"},
{45, nullptr, "GetGameCardAttachmentEvent"},
{46, nullptr, "GetGameCardAttachmentInfo"},
{47, nullptr, "GetTotalSpaceSize"},
{48, D<&IApplicationManagerInterface::GetFreeSpaceSize>, "GetFreeSpaceSize"},
{49, nullptr, "GetSdCardRemovedEvent"},
{52, D<&IApplicationManagerInterface::GetGameCardUpdateDetectionEvent>, "GetGameCardUpdateDetectionEvent"},
{53, nullptr, "DisableApplicationAutoDelete"},
{54, nullptr, "EnableApplicationAutoDelete"},
{55, D<&IApplicationManagerInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"},
{56, nullptr, "SetApplicationTerminateResult"},
{57, nullptr, "ClearApplicationTerminateResult"},
{58, nullptr, "GetLastSdCardMountUnexpectedResult"},
{59, D<&IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"},
{60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
{62, nullptr, "GetGameCardStopper"},
{63, nullptr, "IsSystemProgramInstalled"},
{64, nullptr, "StartApplyDeltaTask"},
{65, nullptr, "GetRequestServerStopper"},
{66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
{67, nullptr, "CancelApplicationApplyDelta"},
{68, nullptr, "ResumeApplicationApplyDelta"},
{69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
{70, D<&IApplicationManagerInterface::ResumeAll>, "ResumeAll"},
{71, D<&IApplicationManagerInterface::GetStorageSize>, "GetStorageSize"},
{80, nullptr, "RequestDownloadApplication"},
{81, nullptr, "RequestDownloadAddOnContent"},
{82, nullptr, "DownloadApplication"},
{83, nullptr, "CheckApplicationResumeRights"},
{84, nullptr, "GetDynamicCommitEvent"},
{85, nullptr, "RequestUpdateApplication2"},
{86, nullptr, "EnableApplicationCrashReport"},
{87, nullptr, "IsApplicationCrashReportEnabled"},
{90, nullptr, "BoostSystemMemoryResourceLimit"},
{91, nullptr, "DeprecatedLaunchApplication"},
{92, nullptr, "GetRunningApplicationProgramId"},
{93, nullptr, "GetMainApplicationProgramIndex"},
{94, nullptr, "LaunchApplication"},
{95, nullptr, "GetApplicationLaunchInfo"},
{96, nullptr, "AcquireApplicationLaunchInfo"},
{97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"},
{98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{99, nullptr, "LaunchDevMenu"},
{100, nullptr, "ResetToFactorySettings"},
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
{103, nullptr, "ResetToFactorySettingsWithPlatformRegion"},
{104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"},
{105, nullptr, "RequestResetToFactorySettingsSecurely"},
{106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"},
{200, nullptr, "CalculateUserSaveDataStatistics"},
{201, nullptr, "DeleteUserSaveDataAll"},
{210, nullptr, "DeleteUserSystemSaveData"},
{211, nullptr, "DeleteSaveData"},
{220, nullptr, "UnregisterNetworkServiceAccount"},
{221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"},
{300, nullptr, "GetApplicationShellEvent"},
{301, nullptr, "PopApplicationShellEventInfo"},
{302, nullptr, "LaunchLibraryApplet"},
{303, nullptr, "TerminateLibraryApplet"},
{304, nullptr, "LaunchSystemApplet"},
{305, nullptr, "TerminateSystemApplet"},
{306, nullptr, "LaunchOverlayApplet"},
{307, nullptr, "TerminateOverlayApplet"},
{400, D<&IApplicationManagerInterface::GetApplicationControlData>, "GetApplicationControlData"},
{401, nullptr, "InvalidateAllApplicationControlCache"},
{402, nullptr, "RequestDownloadApplicationControlData"},
{403, nullptr, "GetMaxApplicationControlCacheCount"},
{404, nullptr, "InvalidateApplicationControlCache"},
{405, nullptr, "ListApplicationControlCacheEntryInfo"},
{406, nullptr, "GetApplicationControlProperty"},
{407, nullptr, "ListApplicationTitle"},
{408, nullptr, "ListApplicationIcon"},
{502, nullptr, "RequestCheckGameCardRegistration"},
{503, nullptr, "RequestGameCardRegistrationGoldPoint"},
{504, nullptr, "RequestRegisterGameCard"},
{505, D<&IApplicationManagerInterface::GetGameCardMountFailureEvent>, "GetGameCardMountFailureEvent"},
{506, nullptr, "IsGameCardInserted"},
{507, nullptr, "EnsureGameCardAccess"},
{508, nullptr, "GetLastGameCardMountFailureResult"},
{509, nullptr, "ListApplicationIdOnGameCard"},
{510, nullptr, "GetGameCardPlatformRegion"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{602, nullptr, "ListAvailableAddOnContent"},
{603, nullptr, "GetOwnedApplicationContentMetaStatus"},
{604, nullptr, "RegisterContentsExternalKey"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{606, nullptr, "GetContentMetaStorage"},
{607, nullptr, "ListAvailableAddOnContent"},
{609, nullptr, "ListAvailabilityAssuredAddOnContent"},
{610, nullptr, "GetInstalledContentMetaStorage"},
{611, nullptr, "PrepareAddOnContent"},
{700, nullptr, "PushDownloadTaskList"},
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{900, nullptr, "GetApplicationRecord"},
{901, nullptr, "GetApplicationRecordProperty"},
{902, nullptr, "EnableApplicationAutoUpdate"},
{903, nullptr, "DisableApplicationAutoUpdate"},
{904, nullptr, "TouchApplication"},
{905, nullptr, "RequestApplicationUpdate"},
{906, D<&IApplicationManagerInterface::IsApplicationUpdateRequested>, "IsApplicationUpdateRequested"},
{907, nullptr, "WithdrawApplicationUpdateRequest"},
{908, nullptr, "ListApplicationRecordInstalledContentMeta"},
{909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
{910, nullptr, "HasApplicationRecord"},
{911, nullptr, "SetPreInstalledApplication"},
{912, nullptr, "ClearPreInstalledApplicationFlag"},
{913, nullptr, "ListAllApplicationRecord"},
{914, nullptr, "HideApplicationRecord"},
{915, nullptr, "ShowApplicationRecord"},
{916, nullptr, "IsApplicationAutoDeleteDisabled"},
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
{1003, nullptr, "RequestVerifyApplication"},
{1004, nullptr, "CorruptContentForDebug"},
{1200, nullptr, "NeedsUpdateVulnerability"},
{1300, D<&IApplicationManagerInterface::IsAnyApplicationEntityInstalled>, "IsAnyApplicationEntityInstalled"},
{1301, nullptr, "DeleteApplicationContentEntities"},
{1302, nullptr, "CleanupUnrecordedApplicationEntity"},
{1303, nullptr, "CleanupAddOnContentsWithNoRights"},
{1304, nullptr, "DeleteApplicationContentEntity"},
{1305, nullptr, "TryDeleteRunningApplicationEntity"},
{1306, nullptr, "TryDeleteRunningApplicationCompletely"},
{1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
{1308, nullptr, "DeleteApplicationCompletelyForDebug"},
{1309, nullptr, "CleanupUnavailableAddOnContents"},
{1310, nullptr, "RequestMoveApplicationEntity"},
{1311, nullptr, "EstimateSizeToMove"},
{1312, nullptr, "HasMovableEntity"},
{1313, nullptr, "CleanupOrphanContents"},
{1314, nullptr, "CheckPreconditionSatisfiedToMove"},
{1400, nullptr, "PrepareShutdown"},
{1500, nullptr, "FormatSdCard"},
{1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
{1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
{1504, nullptr, "InsertSdCard"},
{1505, nullptr, "RemoveSdCard"},
{1506, nullptr, "GetSdCardStartupStatus"},
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
{1701, D<&IApplicationManagerInterface::GetApplicationView>, "GetApplicationView"},
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1704, D<&IApplicationManagerInterface::GetApplicationViewWithPromotionInfo>, "GetApplicationViewWithPromotionInfo"},
{1705, nullptr, "IsPatchAutoDeletableApplication"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
{1803, nullptr, "ListNotificationTask"},
{1900, nullptr, "IsActiveAccount"},
{1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
{1902, nullptr, "GetApplicationTicketInfo"},
{1903, nullptr, "RequestDownloadApplicationPrepurchasedRightsForAccount"},
{2000, nullptr, "GetSystemDeliveryInfo"},
{2001, nullptr, "SelectLatestSystemDeliveryInfo"},
{2002, nullptr, "VerifyDeliveryProtocolVersion"},
{2003, nullptr, "GetApplicationDeliveryInfo"},
{2004, nullptr, "HasAllContentsToDeliver"},
{2005, nullptr, "CompareApplicationDeliveryInfo"},
{2006, nullptr, "CanDeliverApplication"},
{2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
{2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
{2009, nullptr, "EstimateRequiredSize"},
{2010, nullptr, "RequestReceiveApplication"},
{2011, nullptr, "CommitReceiveApplication"},
{2012, nullptr, "GetReceiveApplicationProgress"},
{2013, nullptr, "RequestSendApplication"},
{2014, nullptr, "GetSendApplicationProgress"},
{2015, nullptr, "CompareSystemDeliveryInfo"},
{2016, nullptr, "ListNotCommittedContentMeta"},
{2017, nullptr, "CreateDownloadTask"},
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
{2050, D<&IApplicationManagerInterface::GetApplicationRightsOnClient>, "GetApplicationRightsOnClient"},
{2051, nullptr, "InvalidateRightsIdCache"},
{2100, D<&IApplicationManagerInterface::GetApplicationTerminateResult>, "GetApplicationTerminateResult"},
{2101, nullptr, "GetRawApplicationTerminateResult"},
{2150, nullptr, "CreateRightsEnvironment"},
{2151, nullptr, "DestroyRightsEnvironment"},
{2152, nullptr, "ActivateRightsEnvironment"},
{2153, nullptr, "DeactivateRightsEnvironment"},
{2154, nullptr, "ForceActivateRightsContextForExit"},
{2155, nullptr, "UpdateRightsEnvironmentStatus"},
{2156, nullptr, "CreateRightsEnvironmentForMicroApplication"},
{2160, nullptr, "AddTargetApplicationToRightsEnvironment"},
{2161, nullptr, "SetUsersToRightsEnvironment"},
{2170, nullptr, "GetRightsEnvironmentStatus"},
{2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
{2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"},
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
{2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
{2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
{2250, nullptr, "RequestReportActiveELicence"},
{2300, nullptr, "ListEventLog"},
{2350, nullptr, "PerformAutoUpdateByApplicationId"},
{2351, nullptr, "RequestNoDownloadRightsErrorResolution"},
{2352, nullptr, "RequestResolveNoDownloadRightsError"},
{2353, nullptr, "GetApplicationDownloadTaskInfo"},
{2354, nullptr, "PrioritizeApplicationBackgroundTask"},
{2355, nullptr, "PreferStorageEfficientUpdate"},
{2356, nullptr, "RequestStorageEfficientUpdatePreferable"},
{2357, nullptr, "EnableMultiCoreDownload"},
{2358, nullptr, "DisableMultiCoreDownload"},
{2359, nullptr, "IsMultiCoreDownloadEnabled"},
{2400, nullptr, "GetPromotionInfo"},
{2401, nullptr, "CountPromotionInfo"},
{2402, nullptr, "ListPromotionInfo"},
{2403, nullptr, "ImportPromotionJsonForDebug"},
{2404, nullptr, "ClearPromotionInfoForDebug"},
{2500, nullptr, "ConfirmAvailableTime"},
{2510, nullptr, "CreateApplicationResource"},
{2511, nullptr, "GetApplicationResource"},
{2513, nullptr, "LaunchMicroApplication"},
{2514, nullptr, "ClearTaskOfAsyncTaskManager"},
{2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"},
{2516, nullptr, "EnsureApplicationCertificate"},
{2517, nullptr, "CreateApplicationInstance"},
{2518, nullptr, "UpdateQualificationForDebug"},
{2519, nullptr, "IsQualificationTransitionSupported"},
{2520, nullptr, "IsQualificationTransitionSupportedByProcessId"},
{2521, nullptr, "GetRightsUserChangedEvent"},
{2522, nullptr, "IsRomRedirectionAvailable"},
{2800, nullptr, "GetApplicationIdOfPreomia"},
{3000, nullptr, "RegisterDeviceLockKey"},
{3001, nullptr, "UnregisterDeviceLockKey"},
{3002, nullptr, "VerifyDeviceLockKey"},
{3003, nullptr, "HideApplicationIcon"},
{3004, nullptr, "ShowApplicationIcon"},
{3005, nullptr, "HideApplicationTitle"},
{3006, nullptr, "ShowApplicationTitle"},
{3007, nullptr, "EnableGameCard"},
{3008, nullptr, "DisableGameCard"},
{3009, nullptr, "EnableLocalContentShare"},
{3010, nullptr, "DisableLocalContentShare"},
{3011, nullptr, "IsApplicationIconHidden"},
{3012, nullptr, "IsApplicationTitleHidden"},
{3013, nullptr, "IsGameCardEnabled"},
{3014, nullptr, "IsLocalContentShareEnabled"},
{3050, nullptr, "ListAssignELicenseTaskResult"},
{9999, nullptr, "GetApplicationCertificate"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationManagerInterface::~IApplicationManagerInterface() = default;
Result IApplicationManagerInterface::GetApplicationControlData(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size,
ApplicationControlSource application_control_source, u64 application_id) {
LOG_DEBUG(Service_NS, "called");
R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationControlData(
out_buffer, out_actual_size, application_control_source, application_id));
}
Result IApplicationManagerInterface::GetApplicationDesiredLanguage(
Out<ApplicationLanguage> out_desired_language, u32 supported_languages) {
LOG_DEBUG(Service_NS, "called");
R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationDesiredLanguage(
out_desired_language, supported_languages));
}
Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
Out<u64> out_language_code, ApplicationLanguage application_language) {
LOG_DEBUG(Service_NS, "called");
R_RETURN(
IReadOnlyApplicationControlDataInterface(system).ConvertApplicationLanguageToLanguageCode(
out_language_code, application_language));
}
Result IApplicationManagerInterface::ListApplicationRecord(
OutArray<ApplicationRecord, BufferAttr_HipcMapAlias> out_records, Out<s32> out_count,
s32 offset) {
const auto limit = out_records.size();
LOG_WARNING(Service_NS, "(STUBBED) called");
const auto& cache = system.GetContentProviderUnion();
const auto installed_games = cache.ListEntriesFilterOrigin(
std::nullopt, FileSys::TitleType::Application, FileSys::ContentRecordType::Program);
size_t i = 0;
u8 ii = 24;
for (const auto& [slot, game] : installed_games) {
if (i >= limit) {
break;
}
if (game.title_id == 0 || game.title_id < 0x0100000000001FFFull) {
continue;
}
if (offset > 0) {
offset--;
continue;
}
ApplicationRecord record{};
record.application_id = game.title_id;
record.type = ApplicationRecordType::Installed;
record.unknown = 0; // 2 = needs update
record.unknown2 = ii++;
out_records[i++] = record;
}
*out_count = static_cast<s32>(i);
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationRecordUpdateSystemEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_NS, "(STUBBED) called");
record_update_system_event.Signal();
*out_event = record_update_system_event.GetHandle();
R_SUCCEED();
}
Result IApplicationManagerInterface::GetGameCardMountFailureEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_NS, "(STUBBED) called");
*out_event = gamecard_mount_failure_event.GetHandle();
R_SUCCEED();
}
Result IApplicationManagerInterface::IsAnyApplicationEntityInstalled(
Out<bool> out_is_any_application_entity_installed) {
LOG_WARNING(Service_NS, "(STUBBED) called");
*out_is_any_application_entity_installed = true;
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationView(
OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
const auto size = std::min(out_application_views.size(), application_ids.size());
LOG_WARNING(Service_NS, "(STUBBED) called, size={}", application_ids.size());
for (size_t i = 0; i < size; i++) {
ApplicationView view{};
view.application_id = application_ids[i];
view.unk = 0x70000;
view.flags = 0x401f17;
out_application_views[i] = view;
}
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo(
OutArray<ApplicationViewWithPromotionInfo, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
const auto size = std::min(out_application_views.size(), application_ids.size());
LOG_WARNING(Service_NS, "(STUBBED) called, size={}", application_ids.size());
for (size_t i = 0; i < size; i++) {
ApplicationViewWithPromotionInfo view{};
view.view.application_id = application_ids[i];
view.view.unk = 0x70000;
view.view.flags = 0x401f17;
view.promotion = {};
out_application_views[i] = view;
}
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationRightsOnClient(
OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
Common::UUID account_id, u32 flags, u64 application_id) {
LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}",
flags, application_id, account_id.FormattedString());
if (!out_rights.empty()) {
out_rights[0] = {
.application_id = application_id,
.uid = account_id,
.flags = 0,
.flags2 = 0,
};
*out_count = 1;
} else {
*out_count = 0;
}
R_SUCCEED();
}
Result IApplicationManagerInterface::CheckSdCardMountStatus() {
LOG_DEBUG(Service_NS, "called");
R_RETURN(IContentManagementInterface(system).CheckSdCardMountStatus());
}
Result IApplicationManagerInterface::GetSdCardMountStatusChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_NS, "(STUBBED) called");
*out_event = sd_card_mount_status_event.GetHandle();
R_SUCCEED();
}
Result IApplicationManagerInterface::GetFreeSpaceSize(Out<s64> out_free_space_size,
FileSys::StorageId storage_id) {
LOG_DEBUG(Service_NS, "called");
R_RETURN(IContentManagementInterface(system).GetFreeSpaceSize(out_free_space_size, storage_id));
}
Result IApplicationManagerInterface::GetGameCardUpdateDetectionEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_NS, "(STUBBED) called");
*out_event = gamecard_update_detection_event.GetHandle();
R_SUCCEED();
}
Result IApplicationManagerInterface::ResumeAll() {
LOG_WARNING(Service_NS, "(STUBBED) called");
R_SUCCEED();
}
Result IApplicationManagerInterface::GetStorageSize(Out<s64> out_total_space_size,
Out<s64> out_free_space_size,
FileSys::StorageId storage_id) {
LOG_INFO(Service_NS, "called, storage_id={}", storage_id);
*out_total_space_size = system.GetFileSystemController().GetTotalSpaceSize(storage_id);
*out_free_space_size = system.GetFileSystemController().GetFreeSpaceSize(storage_id);
R_SUCCEED();
}
Result IApplicationManagerInterface::IsApplicationUpdateRequested(Out<bool> out_update_required,
Out<u32> out_update_version,
u64 application_id) {
LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id);
*out_update_required = false;
*out_update_version = 0;
R_SUCCEED();
}
Result IApplicationManagerInterface::CheckApplicationLaunchVersion(u64 application_id) {
LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id);
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationTerminateResult(Out<Result> out_result,
u64 application_id) {
LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id);
*out_result = ResultSuccess;
R_SUCCEED();
}
} // namespace Service::NS

View File

@ -0,0 +1,62 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns_types.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/service.h"
namespace Service::NS {
class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
public:
explicit IApplicationManagerInterface(Core::System& system_);
~IApplicationManagerInterface() override;
Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u32> out_actual_size,
ApplicationControlSource application_control_source,
u64 application_id);
Result GetApplicationDesiredLanguage(Out<ApplicationLanguage> out_desired_language,
u32 supported_languages);
Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code,
ApplicationLanguage application_language);
Result ListApplicationRecord(OutArray<ApplicationRecord, BufferAttr_HipcMapAlias> out_records,
Out<s32> out_count, s32 offset);
Result GetApplicationRecordUpdateSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetGameCardMountFailureEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result IsAnyApplicationEntityInstalled(Out<bool> out_is_any_application_entity_installed);
Result GetApplicationView(
OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids);
Result GetApplicationViewWithPromotionInfo(
OutArray<ApplicationViewWithPromotionInfo, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids);
Result GetApplicationRightsOnClient(
OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
Common::UUID account_id, u32 flags, u64 application_id);
Result CheckSdCardMountStatus();
Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id);
Result GetGameCardUpdateDetectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result ResumeAll();
Result GetStorageSize(Out<s64> out_total_space_size, Out<s64> out_free_space_size,
FileSys::StorageId storage_id);
Result IsApplicationUpdateRequested(Out<bool> out_update_required, Out<u32> out_update_version,
u64 application_id);
Result CheckApplicationLaunchVersion(u64 application_id);
Result GetApplicationTerminateResult(Out<Result> out_result, u64 application_id);
private:
KernelHelpers::ServiceContext service_context;
Event record_update_system_event;
Event sd_card_mount_status_event;
Event gamecard_update_detection_event;
Event gamecard_mount_status_event;
Event gamecard_mount_failure_event;
};
} // namespace Service::NS

Some files were not shown because too many files have changed in this diff Show More