diff options
Diffstat (limited to 'src/android/app')
21 files changed, 1132 insertions, 143 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index ec5f78746..06f22fabe 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +import android.annotation.SuppressLint + plugins { id("com.android.application") id("org.jetbrains.kotlin.android") @@ -35,7 +37,7 @@ android { jvmTarget = "17" } - packagingOptions { + packaging { // This is necessary for libadrenotools custom driver loading jniLibs.useLegacyPackaging = true } @@ -58,6 +60,7 @@ android { versionName = getGitVersion() ndk { + @SuppressLint("ChromeOsAbiSupport") abiFilters += listOf("arm64-v8a") } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index 81474b824..94d5156cf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.activities import android.app.Activity import android.content.Context -import android.content.DialogInterface import android.content.Intent import android.content.res.Configuration import android.graphics.Rect @@ -13,22 +12,30 @@ import android.hardware.Sensor import android.hardware.SensorEvent import android.hardware.SensorEventListener import android.hardware.SensorManager +import android.hardware.display.DisplayManager import android.os.Bundle +import android.view.Display import android.view.InputDevice import android.view.KeyEvent import android.view.MotionEvent import android.view.Surface import android.view.View -import android.view.WindowManager import android.view.inputmethod.InputMethodManager +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity -import androidx.preference.PreferenceManager -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.google.android.material.slider.Slider.OnChangeListener +import androidx.core.content.getSystemService +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.window.layout.WindowInfoTracker +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R -import org.yuzu.yuzu_emu.databinding.DialogSliderBinding -import org.yuzu.yuzu_emu.features.settings.model.Settings +import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel import org.yuzu.yuzu_emu.fragments.EmulationFragment import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.utils.ControllerMappingHelper @@ -44,7 +51,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { private var controllerMappingHelper: ControllerMappingHelper? = null var isActivityRecreated = false - private var menuVisible = false private var emulationFragment: EmulationFragment? = null private lateinit var nfcReader: NfcReader private lateinit var inputHandler: InputHandler @@ -56,6 +62,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { private lateinit var game: Game + private val settingsViewModel: SettingsViewModel by viewModels() + override fun onDestroy() { stopForegroundService(this) super.onDestroy() @@ -64,6 +72,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { override fun onCreate(savedInstanceState: Bundle?) { ThemeHelper.setTheme(this) + settingsViewModel.settings.loadSettings() + super.onCreate(savedInstanceState) if (savedInstanceState == null) { // Get params we were passed @@ -98,6 +108,14 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { inputHandler = InputHandler() inputHandler.initialize() + lifecycleScope.launch(Dispatchers.Main) { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + WindowInfoTracker.getOrCreate(this@EmulationActivity) + .windowLayoutInfo(this@EmulationActivity) + .collect { emulationFragment?.updateCurrentLayout(this@EmulationActivity, it) } + } + } + // Start a foreground service to prevent the app from getting killed in the background val startIntent = Intent(this, ForegroundService::class.java) startForegroundService(startIntent) @@ -241,20 +259,20 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { override fun onAccuracyChanged(sensor: Sensor, i: Int) {} private fun getAdjustedRotation():Int { - val rotation = windowManager.defaultDisplay.rotation; + val rotation = getSystemService<DisplayManager>()!!.getDisplay(Display.DEFAULT_DISPLAY).rotation val config: Configuration = resources.configuration if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 || (config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0) { - return rotation; + return rotation } when (rotation) { - Surface.ROTATION_0 -> return Surface.ROTATION_90; - Surface.ROTATION_90 -> return Surface.ROTATION_0; - Surface.ROTATION_180 -> return Surface.ROTATION_270; - Surface.ROTATION_270 -> return Surface.ROTATION_180; + Surface.ROTATION_0 -> return Surface.ROTATION_90 + Surface.ROTATION_90 -> return Surface.ROTATION_0 + Surface.ROTATION_180 -> return Surface.ROTATION_270 + Surface.ROTATION_270 -> return Surface.ROTATION_180 } - return rotation; + return rotation } private fun restoreState(savedInstanceState: Bundle) { @@ -262,18 +280,13 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { } private fun enableFullscreenImmersive() { - window.attributes.layoutInDisplayCutoutMode = - WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES - - window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) - - // It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar. - window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or - View.SYSTEM_UI_FLAG_FULLSCREEN or - View.SYSTEM_UI_FLAG_IMMERSIVE + WindowCompat.setDecorFitsSystemWindows(window, false) + + WindowInsetsControllerCompat(window, window.decorView).let { controller -> + controller.hide(WindowInsetsCompat.Type.systemBars()) + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } } private fun startMotionSensorListener() { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt new file mode 100644 index 000000000..7006651d0 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.adapters + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import org.yuzu.yuzu_emu.YuzuApplication +import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding +import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment +import org.yuzu.yuzu_emu.model.License + +class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) : + RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(), + View.OnClickListener { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder { + val binding = + ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false) + binding.root.setOnClickListener(this) + return LicenseViewHolder(binding) + } + + override fun getItemCount(): Int = licenses.size + + override fun onBindViewHolder(holder: LicenseViewHolder, position: Int) { + holder.bind(licenses[position]) + } + + override fun onClick(view: View) { + val license = (view.tag as LicenseViewHolder).license + LicenseBottomSheetDialogFragment.newInstance(license) + .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG) + } + + inner class LicenseViewHolder(val binding: ListItemSettingBinding) : ViewHolder(binding.root) { + lateinit var license: License + + init { + itemView.tag = this + } + + fun bind(license: License) { + this.license = license + + val context = YuzuApplication.appContext + binding.textSettingName.text = context.getString(license.titleId) + binding.textSettingDescription.text = context.getString(license.descriptionId) + } + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/ui/KeyboardDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/ui/KeyboardDialogFragment.kt index 4b12809bc..607a3d506 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/ui/KeyboardDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/ui/KeyboardDialogFragment.kt @@ -63,7 +63,7 @@ class KeyboardDialogFragment : DialogFragment() { val headerText = config.header_text!!.ifEmpty { resources.getString(R.string.software_keyboard) } val okText = - config.ok_text!!.ifEmpty { resources.getString(android.R.string.ok) } + config.ok_text!!.ifEmpty { resources.getString(R.string.submit) } return MaterialAlertDialogBuilder(requireContext()) .setTitle(headerText) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index 23c31e13a..8df20b928 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt @@ -39,7 +39,7 @@ class Settings { val isEmpty: Boolean get() = sections.isEmpty() - fun loadSettings(view: SettingsActivityView) { + fun loadSettings(view: SettingsActivityView? = null) { sections = SettingsSectionMap() loadYuzuSettings(view) if (!TextUtils.isEmpty(gameId)) { @@ -48,13 +48,13 @@ class Settings { isLoaded = true } - private fun loadYuzuSettings(view: SettingsActivityView) { + private fun loadYuzuSettings(view: SettingsActivityView?) { for ((fileName) in configFileSectionsMap) { sections.putAll(SettingsFile.readFile(fileName, view)) } } - private fun loadCustomGameSettings(gameId: String, view: SettingsActivityView) { + private fun loadCustomGameSettings(gameId: String, view: SettingsActivityView?) { // Custom game settings mergeSections(SettingsFile.readCustomGameSettings(gameId, view)) } @@ -108,6 +108,7 @@ class Settings { const val SECTION_AUDIO = "Audio" const val SECTION_CPU = "Cpu" const val SECTION_THEME = "Theme" + const val SECTION_DEBUG = "Debug" const val PREF_OVERLAY_INIT = "OverlayInit" const val PREF_CONTROL_SCALE = "controlScale" diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt index 8c1af6396..a3ef59c2f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt @@ -6,10 +6,9 @@ package org.yuzu.yuzu_emu.features.settings.model.view import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting class SubmenuSetting( - setting: AbstractSetting?, titleId: Int, descriptionId: Int, val menuKey: String -) : SettingsItem(setting, titleId, descriptionId) { +) : SettingsItem(null, titleId, descriptionId) { override val type = TYPE_SUBMENU } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 7d55c5b2f..061046b2e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -68,6 +68,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) Settings.SECTION_RENDERER -> addGraphicsSettings(sl) Settings.SECTION_AUDIO -> addAudioSettings(sl) Settings.SECTION_THEME -> addThemeSettings(sl) + Settings.SECTION_DEBUG -> addDebugSettings(sl) else -> { fragmentView.showToastMessage("Unimplemented menu", false) return @@ -78,11 +79,10 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) } private fun addConfigSettings(sl: ArrayList<SettingsItem>) { - settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_advanced_settings)) + settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.advanced_settings)) sl.apply { add( SubmenuSetting( - null, R.string.preferences_general, 0, Settings.SECTION_GENERAL @@ -90,7 +90,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) add( SubmenuSetting( - null, R.string.preferences_system, 0, Settings.SECTION_SYSTEM @@ -98,7 +97,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) add( SubmenuSetting( - null, R.string.preferences_graphics, 0, Settings.SECTION_RENDERER @@ -106,13 +104,19 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) add( SubmenuSetting( - null, R.string.preferences_audio, 0, Settings.SECTION_AUDIO ) ) add( + SubmenuSetting( + R.string.preferences_debug, + 0, + Settings.SECTION_DEBUG + ) + ) + add( RunnableSetting( R.string.reset_to_default, 0, @@ -223,17 +227,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) { settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_graphics)) sl.apply { - add( - SingleChoiceSetting( - IntSetting.RENDERER_BACKEND, - R.string.renderer_api, - 0, - R.array.rendererApiNames, - R.array.rendererApiValues, - IntSetting.RENDERER_BACKEND.key, - IntSetting.RENDERER_BACKEND.defaultValue - ) - ) + add( SingleChoiceSetting( IntSetting.RENDERER_ACCURACY, @@ -327,15 +321,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) IntSetting.RENDERER_ASYNCHRONOUS_SHADERS.defaultValue ) ) - add( - SwitchSetting( - IntSetting.RENDERER_DEBUG, - R.string.renderer_debug, - R.string.renderer_debug_description, - IntSetting.RENDERER_DEBUG.key, - IntSetting.RENDERER_DEBUG.defaultValue - ) - ) } } @@ -451,4 +436,30 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) } } + + private fun addDebugSettings(sl: ArrayList<SettingsItem>) { + settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_debug)) + sl.apply { + add( + SingleChoiceSetting( + IntSetting.RENDERER_BACKEND, + R.string.renderer_api, + 0, + R.array.rendererApiNames, + R.array.rendererApiValues, + IntSetting.RENDERER_BACKEND.key, + IntSetting.RENDERER_BACKEND.defaultValue + ) + ) + add( + SwitchSetting( + IntSetting.RENDERER_DEBUG, + R.string.renderer_debug, + R.string.renderer_debug_description, + IntSetting.RENDERER_DEBUG.key, + IntSetting.RENDERER_DEBUG.defaultValue + ) + ) + } + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt index c502fdca0..e29bca11d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt @@ -37,7 +37,7 @@ object SettingsFile { private fun readFile( ini: File?, isCustomGame: Boolean, - view: SettingsActivityView? + view: SettingsActivityView? = null ): HashMap<String, SettingSection?> { val sections: HashMap<String, SettingSection?> = SettingsSectionMap() var reader: BufferedReader? = null @@ -74,10 +74,13 @@ object SettingsFile { return sections } - fun readFile(fileName: String, view: SettingsActivityView): HashMap<String, SettingSection?> { + fun readFile(fileName: String, view: SettingsActivityView?): HashMap<String, SettingSection?> { return readFile(getSettingsFile(fileName), false, view) } + fun readFile(fileName: String): HashMap<String, SettingSection?> = + readFile(getSettingsFile(fileName), false) + /** * Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it @@ -88,7 +91,7 @@ object SettingsFile { */ fun readCustomGameSettings( gameId: String, - view: SettingsActivityView + view: SettingsActivityView? ): HashMap<String, SettingSection?> { return readFile(getCustomGameSettingsFile(gameId), true, view) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt index 0314feff6..c92e2755c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt @@ -15,13 +15,12 @@ import android.view.View import android.view.ViewGroup import android.view.ViewGroup.MarginLayoutParams import android.widget.Toast -import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.navigation.fragment.findNavController +import androidx.navigation.findNavController import com.google.android.material.transition.MaterialSharedAxis import org.yuzu.yuzu_emu.BuildConfig import org.yuzu.yuzu_emu.R @@ -38,6 +37,7 @@ class AboutFragment : Fragment() { super.onCreate(savedInstanceState) enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) + reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) } override fun onCreateView( @@ -54,7 +54,7 @@ class AboutFragment : Fragment() { homeViewModel.setStatusBarShadeVisibility(visible = false) binding.toolbarAbout.setNavigationOnClickListener { - parentFragmentManager.primaryNavigationFragment?.findNavController()?.popBackStack() + binding.root.findNavController().popBackStack() } binding.imageLogo.setOnLongClickListener { @@ -67,6 +67,10 @@ class AboutFragment : Fragment() { } binding.buttonContributors.setOnClickListener { openLink(getString(R.string.contributors_link)) } + binding.buttonLicenses.setOnClickListener { + exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) + binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment) + } binding.textBuildHash.text = BuildConfig.GIT_HASH binding.buttonBuildHash.setOnClickListener { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index e00f02f86..41b1a6e23 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -8,10 +8,13 @@ import android.app.AlertDialog import android.content.Context import android.content.DialogInterface import android.content.SharedPreferences +import android.content.pm.ActivityInfo +import android.content.res.Resources import android.graphics.Color import android.os.Bundle import android.os.Handler import android.os.Looper +import android.util.TypedValue import android.view.* import android.widget.TextView import androidx.activity.OnBackPressedCallback @@ -20,8 +23,11 @@ import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.Insets import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.preference.PreferenceManager +import androidx.window.layout.FoldingFeature +import androidx.window.layout.WindowLayoutInfo import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.slider.Slider import org.yuzu.yuzu_emu.NativeLibrary @@ -211,6 +217,33 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } } + private val Number.toPx get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt() + + fun updateCurrentLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) { + val isFolding = (newLayoutInfo.displayFeatures.find { it is FoldingFeature } as? FoldingFeature)?.let { + if (it.isSeparating) { + emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) { + binding.surfaceEmulation.layoutParams.height = it.bounds.top + binding.inGameMenu.layoutParams.height = it.bounds.bottom + binding.overlayContainer.layoutParams.height = it.bounds.bottom - 48.toPx + binding.overlayContainer.updatePadding(0, 0, 0, 24.toPx) + } + } + it.isSeparating + } ?: false + if (!isFolding) { + binding.surfaceEmulation.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT + binding.inGameMenu.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT + binding.overlayContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT + binding.overlayContainer.updatePadding(0, 0, 0, 0) + emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE + } + binding.surfaceInputOverlay.requestLayout() + binding.inGameMenu.requestLayout() + binding.overlayContainer.requestLayout() + } + override fun surfaceCreated(holder: SurfaceHolder) { // We purposely don't do anything here. // All work is done in surfaceChanged, which we are guaranteed to get even for surface creation. @@ -281,6 +314,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { .setPositiveButton(android.R.string.ok) { _, _ -> refreshInputOverlay() } + .setNegativeButton(android.R.string.cancel, null) .setNeutralButton(R.string.emulation_toggle_all) { _, _ -> } .show() diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicenseBottomSheetDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicenseBottomSheetDialogFragment.kt new file mode 100644 index 000000000..78419191c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicenseBottomSheetDialogFragment.kt @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import org.yuzu.yuzu_emu.databinding.DialogLicenseBinding +import org.yuzu.yuzu_emu.model.License +import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable + +class LicenseBottomSheetDialogFragment : BottomSheetDialogFragment() { + private var _binding: DialogLicenseBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = DialogLicenseBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + BottomSheetBehavior.from<View>(view.parent as View).state = + BottomSheetBehavior.STATE_HALF_EXPANDED + + val license = requireArguments().parcelable<License>(LICENSE)!! + + binding.apply { + textTitle.setText(license.titleId) + textLink.setText(license.linkId) + textCopyright.setText(license.copyrightId) + textLicense.setText(license.licenseId) + } + } + + companion object { + const val TAG = "LicenseBottomSheetDialogFragment" + + const val LICENSE = "License" + + fun newInstance( + license: License + ): LicenseBottomSheetDialogFragment { + val dialog = LicenseBottomSheetDialogFragment() + val bundle = Bundle() + bundle.putParcelable(LICENSE, license) + dialog.arguments = bundle + return dialog + } + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt new file mode 100644 index 000000000..59141e823 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt @@ -0,0 +1,137 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.MarginLayoutParams +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.transition.MaterialSharedAxis +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.adapters.LicenseAdapter +import org.yuzu.yuzu_emu.databinding.FragmentLicensesBinding +import org.yuzu.yuzu_emu.model.HomeViewModel +import org.yuzu.yuzu_emu.model.License + +class LicensesFragment : Fragment() { + private var _binding: FragmentLicensesBinding? = null + private val binding get() = _binding!! + + private val homeViewModel: HomeViewModel by activityViewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) + returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentLicensesBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + homeViewModel.setNavigationVisibility(visible = false, animated = true) + homeViewModel.setStatusBarShadeVisibility(visible = false) + + binding.toolbarLicenses.setNavigationOnClickListener { + binding.root.findNavController().popBackStack() + } + + val licenses = listOf( + License( + R.string.license_fidelityfx_fsr, + R.string.license_fidelityfx_fsr_description, + R.string.license_fidelityfx_fsr_link, + R.string.license_fidelityfx_fsr_copyright, + R.string.license_fidelityfx_fsr_text + ), + License( + R.string.license_cubeb, + R.string.license_cubeb_description, + R.string.license_cubeb_link, + R.string.license_cubeb_copyright, + R.string.license_cubeb_text + ), + License( + R.string.license_dynarmic, + R.string.license_dynarmic_description, + R.string.license_dynarmic_link, + R.string.license_dynarmic_copyright, + R.string.license_dynarmic_text + ), + License( + R.string.license_ffmpeg, + R.string.license_ffmpeg_description, + R.string.license_ffmpeg_link, + R.string.license_ffmpeg_copyright, + R.string.license_ffmpeg_text + ), + License( + R.string.license_opus, + R.string.license_opus_description, + R.string.license_opus_link, + R.string.license_opus_copyright, + R.string.license_opus_text + ), + License( + R.string.license_sirit, + R.string.license_sirit_description, + R.string.license_sirit_link, + R.string.license_sirit_copyright, + R.string.license_sirit_text + ), + License( + R.string.license_adreno_tools, + R.string.license_adreno_tools_description, + R.string.license_adreno_tools_link, + R.string.license_adreno_tools_copyright, + R.string.license_adreno_tools_text + ) + ) + + binding.listLicenses.apply { + layoutManager = LinearLayoutManager(requireContext()) + adapter = LicenseAdapter(requireActivity() as AppCompatActivity, licenses) + } + + setInsets() + } + + private fun setInsets() = + ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat -> + val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) + val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) + + val leftInsets = barInsets.left + cutoutInsets.left + val rightInsets = barInsets.right + cutoutInsets.right + + val mlpAppBar = binding.appbarLicenses.layoutParams as MarginLayoutParams + mlpAppBar.leftMargin = leftInsets + mlpAppBar.rightMargin = rightInsets + binding.appbarLicenses.layoutParams = mlpAppBar + + val mlpScrollAbout = binding.listLicenses.layoutParams as MarginLayoutParams + mlpScrollAbout.leftMargin = leftInsets + mlpScrollAbout.rightMargin = rightInsets + binding.listLicenses.layoutParams = mlpScrollAbout + + binding.listLicenses.updatePadding(bottom = barInsets.bottom) + + windowInsets + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/License.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/License.kt new file mode 100644 index 000000000..f24d5cf34 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/License.kt @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class License( + val titleId: Int, + val descriptionId: Int, + val linkId: Int, + val copyrightId: Int, + val licenseId: Int +) : Parcelable diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 6805efb55..124f62f08 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -35,6 +35,7 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.databinding.ActivityMainBinding import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding import org.yuzu.yuzu_emu.features.settings.model.Settings +import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment @@ -51,6 +52,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { private val homeViewModel: HomeViewModel by viewModels() private val gamesViewModel: GamesViewModel by viewModels() + private val settingsViewModel: SettingsViewModel by viewModels() override var themeId: Int = 0 @@ -58,6 +60,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { val splashScreen = installSplashScreen() splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } + settingsViewModel.settings.loadSettings() + ThemeHelper.setTheme(this) super.onCreate(savedInstanceState) diff --git a/src/android/app/src/main/res/layout/dialog_license.xml b/src/android/app/src/main/res/layout/dialog_license.xml new file mode 100644 index 000000000..866857562 --- /dev/null +++ b/src/android/app/src/main/res/layout/dialog_license.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools"> + + <androidx.core.widget.NestedScrollView + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_marginHorizontal="16dp"> + + <com.google.android.material.bottomsheet.BottomSheetDragHandleView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal"/> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.HeadlineLarge" + android:id="@+id/text_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + tools:text="@string/license_adreno_tools" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.BodyLarge" + android:id="@+id/text_link" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:layout_marginTop="16dp" + android:autoLink="all" + tools:text="@string/license_adreno_tools_link" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.BodyLarge" + android:id="@+id/text_copyright" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:layout_marginTop="16dp" + android:textStyle="bold" + tools:text="@string/license_adreno_tools_copyright" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.BodyMedium" + android:id="@+id/text_license" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginVertical="16dp" + android:autoLink="all" + tools:text="@string/license_adreno_tools_text" /> + + </LinearLayout> + + </androidx.core.widget.NestedScrollView> + +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml index 549f00aa5..3e1d98451 100644 --- a/src/android/app/src/main/res/layout/fragment_about.xml +++ b/src/android/app/src/main/res/layout/fragment_about.xml @@ -115,6 +115,39 @@ android:layout_marginHorizontal="20dp" /> <LinearLayout + android:id="@+id/button_licenses" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingVertical="16dp" + android:paddingHorizontal="16dp" + android:background="?attr/selectableItemBackground" + android:orientation="vertical"> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.TitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:textAlignment="viewStart" + android:text="@string/licenses" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.BodyMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="6dp" + android:textAlignment="viewStart" + android:text="@string/licenses_description" /> + + </LinearLayout> + + <com.google.android.material.divider.MaterialDivider + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="20dp" /> + + <LinearLayout android:id="@+id/button_build_hash" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/src/android/app/src/main/res/layout/fragment_emulation.xml b/src/android/app/src/main/res/layout/fragment_emulation.xml index 74ec512af..940dbd4bf 100644 --- a/src/android/app/src/main/res/layout/fragment_emulation.xml +++ b/src/android/app/src/main/res/layout/fragment_emulation.xml @@ -20,6 +20,12 @@ android:focusable="false" android:focusableInTouchMode="false" /> + <FrameLayout + android:id="@+id/overlay_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="bottom"> + <!-- This is the onscreen input overlay --> <org.yuzu.yuzu_emu.overlay.InputOverlay android:id="@+id/surface_input_overlay" @@ -48,6 +54,7 @@ android:layout_gravity="center" android:text="@string/emulation_done" android:visibility="gone" /> + </FrameLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout> @@ -55,7 +62,7 @@ android:id="@+id/in_game_menu" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_gravity="start" + android:layout_gravity="start|bottom" app:headerLayout="@layout/header_in_game" app:menu="@menu/menu_in_game" /> diff --git a/src/android/app/src/main/res/layout/fragment_licenses.xml b/src/android/app/src/main/res/layout/fragment_licenses.xml new file mode 100644 index 000000000..6b31ff5b4 --- /dev/null +++ b/src/android/app/src/main/res/layout/fragment_licenses.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/coordinator_licenses" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/colorSurface"> + + <com.google.android.material.appbar.AppBarLayout + android:id="@+id/appbar_licenses" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fitsSystemWindows="true"> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar_licenses" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + app:title="@string/licenses" + app:navigationIcon="@drawable/ic_back" /> + + </com.google.android.material.appbar.AppBarLayout> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/list_licenses" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> + +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/src/android/app/src/main/res/navigation/home_navigation.xml b/src/android/app/src/main/res/navigation/home_navigation.xml index 2275ddc32..48072683e 100644 --- a/src/android/app/src/main/res/navigation/home_navigation.xml +++ b/src/android/app/src/main/res/navigation/home_navigation.xml @@ -40,11 +40,20 @@ <fragment android:id="@+id/aboutFragment" android:name="org.yuzu.yuzu_emu.fragments.AboutFragment" - android:label="AboutFragment" /> + android:label="AboutFragment" > + <action + android:id="@+id/action_aboutFragment_to_licensesFragment" + app:destination="@id/licensesFragment" /> + </fragment> <fragment android:id="@+id/earlyAccessFragment" android:name="org.yuzu.yuzu_emu.fragments.EarlyAccessFragment" android:label="EarlyAccessFragment" /> + <fragment + android:id="@+id/licensesFragment" + android:name="org.yuzu.yuzu_emu.fragments.LicensesFragment" + android:label="LicensesFragment" /> + </navigation> diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index fa88770c8..ea20cb17c 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -2,67 +2,67 @@ <resources> <string-array name="regionNames"> - <item>@string/region_auto</item> - <item>@string/region_japan</item> - <item>@string/region_usa</item> - <item>@string/region_europe</item> + <item>@string/auto</item> <item>@string/region_australia</item> <item>@string/region_china</item> + <item>@string/region_europe</item> + <item>@string/region_japan</item> <item>@string/region_korea</item> <item>@string/region_taiwan</item> + <item>@string/region_usa</item> </string-array> <integer-array name="regionValues"> <item>-1</item> - <item>0</item> - <item>1</item> - <item>2</item> <item>3</item> <item>4</item> + <item>2</item> + <item>0</item> <item>5</item> <item>6</item> + <item>1</item> </integer-array> <string-array name="languageNames"> - <item>@string/language_japanese</item> + <item>@string/language_brazilian_portuguese</item> + <item>@string/language_british_english</item> + <item>@string/language_canadian_french</item> + <item>@string/language_chinese</item> + <item>@string/language_dutch</item> <item>@string/language_english</item> <item>@string/language_french</item> <item>@string/langauge_german</item> <item>@string/language_italian</item> - <item>@string/language_spanish</item> - <item>@string/language_chinese</item> + <item>@string/language_japanese</item> <item>@string/language_korean</item> - <item>@string/language_dutch</item> + <item>@string/language_latin_american_spanish</item> <item>@string/language_portuguese</item> <item>@string/language_russian</item> - <item>@string/language_taiwanese</item> - <item>@string/language_british_english</item> - <item>@string/language_canadian_french</item> - <item>@string/language_latin_american_spanish</item> <item>@string/language_simplified_chinese</item> + <item>@string/language_spanish</item> + <item>@string/language_taiwanese</item> <item>@string/language_traditional_chinese</item> - <item>@string/language_brazilian_portuguese</item> </string-array> <integer-array name="languageValues"> - <item>0</item> + <item>17</item> + <item>12</item> + <item>13</item> + <item>6</item> + <item>8</item> <item>1</item> <item>2</item> <item>3</item> <item>4</item> - <item>5</item> - <item>6</item> + <item>0</item> <item>7</item> - <item>8</item> + <item>14</item> <item>9</item> <item>10</item> - <item>11</item> - <item>12</item> - <item>13</item> - <item>14</item> <item>15</item> + <item>5</item> + <item>11</item> <item>16</item> - <item>17</item> </integer-array> <string-array name="rendererApiNames"> @@ -166,7 +166,7 @@ </integer-array> <string-array name="cpuAccuracyNames"> - <item>@string/cpu_accuracy_auto</item> + <item>@string/auto</item> <item>@string/cpu_accuracy_accurate</item> <item>@string/cpu_accuracy_unsafe</item> <item>@string/cpu_accuracy_paranoid</item> diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 1646b90eb..0ae69afb4 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -41,7 +41,7 @@ <string name="add_games_warning">Skip selecting games folder?</string> <string name="add_games_warning_description">Games won\'t be displayed in the Games list if a folder isn\'t selected.</string> <string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string> - <string name="home_search_games">Search Games</string> + <string name="home_search_games">Search games</string> <string name="games_dir_selected">Games directory selected</string> <string name="install_prod_keys">Install prod.keys</string> <string name="install_prod_keys_description">Required to decrypt retail games</string> @@ -77,8 +77,8 @@ <string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string> <string name="advanced_settings">Advanced settings</string> <string name="settings_description">Configure emulator settings</string> - <string name="search_recently_played">Recently Played</string> - <string name="search_recently_added">Recently Added</string> + <string name="search_recently_played">Recently played</string> + <string name="search_recently_added">Recently added</string> <string name="search_retail">Retail</string> <string name="search_homebrew">Homebrew</string> <string name="open_user_folder">Open yuzu folder</string> @@ -113,6 +113,7 @@ <string name="contributors">Contributors</string> <string name="contributors_description">Made with \u2764 from the yuzu team</string> <string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string> + <string name="licenses_description">Projects that make yuzu for Android possible</string> <string name="build">Build</string> <string name="support_link">https://discord.gg/u77vRWY</string> <string name="website_link">https://yuzu-emu.org/</string> @@ -133,39 +134,39 @@ <string name="are_you_interested">Are you interested?</string> <!-- General settings strings --> - <string name="frame_limit_enable">Enable limit speed</string> - <string name="frame_limit_enable_description">When enabled, emulation speed will be limited to a specified percentage of normal speed.</string> + <string name="frame_limit_enable">Limit speed</string> + <string name="frame_limit_enable_description">Limits emulation speed to a specified percentage of normal speed.</string> <string name="frame_limit_slider">Limit speed percent</string> - <string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit.</string> + <string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit.</string> <string name="cpu_accuracy">CPU accuracy</string> <!-- System settings strings --> - <string name="use_docked_mode">Docked mode</string> - <string name="use_docked_mode_description">Emulates in docked mode, which increases the resolution at the expense of performance.</string> + <string name="use_docked_mode">Docked Mode</string> + <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string> <string name="emulated_region">Emulated region</string> <string name="emulated_language">Emulated language</string> - <string name="select_rtc_date">Select RTC Date</string> - <string name="select_rtc_time">Select RTC Time</string> - <string name="use_custom_rtc">Enable Custom RTC</string> - <string name="use_custom_rtc_description">This setting allows you to set a custom real time clock separate from your current system time</string> - <string name="set_custom_rtc">Set Custom RTC</string> + <string name="select_rtc_date">Select RTC date</string> + <string name="select_rtc_time">Select RTC time</string> + <string name="use_custom_rtc">Custom RTC</string> + <string name="use_custom_rtc_description">Allows you to set a custom real-time clock separate from your current system time.</string> + <string name="set_custom_rtc">Set custom RTC</string> <!-- Graphics settings strings --> <string name="renderer_api">API</string> <string name="renderer_accuracy">Accuracy level</string> - <string name="renderer_resolution">Resolution</string> + <string name="renderer_resolution">Resolution (Handheld/Docked)</string> <string name="renderer_vsync">VSync mode</string> - <string name="renderer_aspect_ratio">Aspect Ratio</string> - <string name="renderer_scaling_filter">Window Adapting Filter</string> - <string name="renderer_anti_aliasing">Anti-Aliasing Method</string> + <string name="renderer_aspect_ratio">Aspect ratio</string> + <string name="renderer_scaling_filter">Window adapting filter</string> + <string name="renderer_anti_aliasing">Anti-aliasing method</string> <string name="renderer_force_max_clock">Force maximum clocks (Adreno only)</string> <string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string> <string name="renderer_asynchronous_shaders">Use asynchronous shaders</string> - <string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, which will reduce stutter but may introduce glitches.</string> - <string name="renderer_debug">Enable graphics debugging</string> - <string name="renderer_debug_description">When checked, the graphics API enters a slower debugging mode.</string> - <string name="use_disk_shader_cache">Use disk shader cache</string> - <string name="use_disk_shader_cache_description">Reduce stuttering by storing and loading generated shaders to disk.</string> + <string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, reducing stutter but may introduce glitches.</string> + <string name="renderer_debug">Graphics debugging</string> + <string name="renderer_debug_description">Sets the graphics API to a slow debugging mode.</string> + <string name="use_disk_shader_cache">Disk shader cache</string> + <string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string> <!-- Audio settings strings --> <string name="audio_volume">Volume</string> @@ -180,10 +181,12 @@ <string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string> <string name="reset_to_default">Reset to default</string> <string name="reset_all_settings">Reset all settings?</string> - <string name="reset_all_settings_description">All Advanced Settings will be reset to their default configuration. This can not be undone.</string> + <string name="reset_all_settings_description">All advanced settings will be reset to their default configuration. This can not be undone.</string> <string name="settings_reset">Settings reset</string> <string name="close">Close</string> - <string name="learn_more">Learn More</string> + <string name="learn_more">Learn more</string> + <string name="auto">Auto</string> + <string name="submit">Submit</string> <!-- GPU driver installation --> <string name="select_gpu_driver">Select GPU driver</string> @@ -197,13 +200,13 @@ <string name="installing_driver">Installing driver…</string> <!-- Preferences Screen --> - <string name="preferences_advanced_settings">Advanced Settings</string> <string name="preferences_settings">Settings</string> <string name="preferences_general">General</string> <string name="preferences_system">System</string> <string name="preferences_graphics">Graphics</string> <string name="preferences_audio">Audio</string> <string name="preferences_theme">Theme and color</string> + <string name="preferences_debug">Debug</string> <!-- ROM loading errors --> <string name="loader_error_encrypted">Your ROM is encrypted</string> @@ -215,29 +218,29 @@ <string name="loader_error_file_not_found">ROM file does not exist</string> <!-- Emulation Menu --> - <string name="emulation_exit">Exit Emulation</string> + <string name="emulation_exit">Exit emulation</string> <string name="emulation_done">Done</string> - <string name="emulation_fps_counter">FPS Counter</string> - <string name="emulation_toggle_controls">Toggle Controls</string> - <string name="emulation_rel_stick_center">Relative Stick Center</string> - <string name="emulation_dpad_slide">DPad Slide</string> - <string name="emulation_haptics">Haptics</string> - <string name="emulation_show_overlay">Show Overlay</string> - <string name="emulation_toggle_all">Toggle All</string> - <string name="emulation_control_adjust">Adjust Overlay</string> + <string name="emulation_fps_counter">FPS counter</string> + <string name="emulation_toggle_controls">Toggle controls</string> + <string name="emulation_rel_stick_center">Relative stick center</string> + <string name="emulation_dpad_slide">D-pad slide</string> + <string name="emulation_haptics">Touch haptics</string> + <string name="emulation_show_overlay">Show overlay</string> + <string name="emulation_toggle_all">Toggle all</string> + <string name="emulation_control_adjust">Adjust overlay</string> <string name="emulation_control_scale">Scale</string> <string name="emulation_control_opacity">Opacity</string> - <string name="emulation_touch_overlay_reset">Reset Overlay</string> - <string name="emulation_touch_overlay_edit">Edit Overlay</string> - <string name="emulation_pause">Pause Emulation</string> - <string name="emulation_unpause">Unpause Emulation</string> - <string name="emulation_input_overlay">Overlay Options</string> + <string name="emulation_touch_overlay_reset">Reset overlay</string> + <string name="emulation_touch_overlay_edit">Edit overlay</string> + <string name="emulation_pause">Pause emulation</string> + <string name="emulation_unpause">Unpause emulation</string> + <string name="emulation_input_overlay">Overlay options</string> <string name="emulation_game_loading">Game loading…</string> - <string name="load_settings">Loading Settings…</string> + <string name="load_settings">Loading settings…</string> <!-- Software keyboard --> - <string name="software_keyboard">Software Keyboard</string> + <string name="software_keyboard">Software keyboard</string> <!-- Errors and warnings --> <string name="abort_button">Abort</string> @@ -251,7 +254,6 @@ <string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string> <!-- Region Names --> - <string name="region_auto">Auto-select</string> <string name="region_japan">Japan</string> <string name="region_usa">USA</string> <string name="region_europe">Europe</string> @@ -321,18 +323,17 @@ <string name="ratio_force_four_three">Force 4:3</string> <string name="ratio_force_twenty_one_nine">Force 21:9</string> <string name="ratio_force_sixteen_ten">Force 16:10</string> - <string name="ratio_stretch">Stretch to Window</string> + <string name="ratio_stretch">Stretch to window</string> <!-- CPU Accuracy --> - <string name="cpu_accuracy_auto">Auto</string> <string name="cpu_accuracy_accurate">Accurate</string> <string name="cpu_accuracy_unsafe">Unsafe</string> <string name="cpu_accuracy_paranoid">Paranoid (Slow)</string> <!-- Gamepad Buttons --> - <string name="gamepad_d_pad">D-Pad</string> - <string name="gamepad_left_stick">Left Stick</string> - <string name="gamepad_right_stick">Right Stick</string> + <string name="gamepad_d_pad">D-pad</string> + <string name="gamepad_left_stick">Left stick</string> + <string name="gamepad_right_stick">Right stick</string> <string name="gamepad_home">Home</string> <string name="gamepad_screenshot">Screenshot</string> @@ -341,18 +342,525 @@ <string name="building_shaders">Building shaders</string> <!-- Theme options --> - <string name="change_app_theme">Change App Theme</string> + <string name="change_app_theme">Change app theme</string> <string name="theme_default">Default</string> <string name="theme_material_you">Material You</string> <!-- Theme Modes --> - <string name="change_theme_mode">Change Theme Mode</string> + <string name="change_theme_mode">Change theme mode</string> <string name="theme_mode_follow_system">Follow System</string> <string name="theme_mode_light">Light</string> <string name="theme_mode_dark">Dark</string> <!-- Black backgrounds theme --> - <string name="use_black_backgrounds">Use Black Backgrounds</string> + <string name="use_black_backgrounds">Black backgrounds</string> <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string> + <!-- Licenses screen strings --> + <string name="licenses">Licenses</string> + <string name="license_fidelityfx_fsr" translatable="false">FidelityFX-FSR</string> + <string name="license_fidelityfx_fsr_description">High-quality upscaling from AMD</string> + <string name="license_fidelityfx_fsr_link" translatable="false">https://github.com/GPUOpen-Effects/FidelityFX-FSR</string> + <string name="license_fidelityfx_fsr_copyright" translatable="false">Copyright © 2021 Advanced Micro Devices, Inc.</string> + <string name="license_fidelityfx_fsr_text" translatable="false"> +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the \"Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:\n\n + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.\n\n + +THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + </string> + <string name="license_cubeb" translatable="false">cubeb</string> + <string name="license_cubeb_description" translatable="false">Cross platform audio library</string> + <string name="license_cubeb_link" translatable="false">https://github.com/mozilla/cubeb</string> + <string name="license_cubeb_copyright" translatable="false">Copyright © 2011 Mozilla Foundation</string> + <string name="license_cubeb_text" translatable="false"> +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies.\n\n + +THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + </string> + <string name="license_dynarmic" translatable="false">Dynarmic</string> + <string name="license_dynarmic_description" translatable="false">An ARM dynamic recompiler</string> + <string name="license_dynarmic_link" translatable="false">https://github.com/merryhime/dynarmic</string> + <string name="license_dynarmic_copyright" translatable="false">Copyright © 2017 merryhime</string> + <string name="license_dynarmic_text" translatable="false"> +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted.\n\n + +THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + </string> + <string name="license_ffmpeg" translatable="false">FFmpeg</string> + <string name="license_ffmpeg_description" translatable="false">FFmpeg is a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata.</string> + <string name="license_ffmpeg_link" translatable="false">https://github.com/FFmpeg/FFmpeg</string> + <string name="license_ffmpeg_copyright" translatable="false">Copyright © 1991, 1999 Free Software Foundation, Inc.</string> + <string name="license_ffmpeg_text" translatable="false"> +GNU LESSER GENERAL PUBLIC LICENSE\n +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called \"this License\"). +Each licensee is addressed as \"you\".\n\n + + A \"library\" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables.\n\n + + The \"Library\", below, refers to any such software library or work +which has been distributed under these terms. A \"work based on the +Library\" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term \"modification\".)\n\n + + \"Source code\" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library.\n\n + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does.\n\n + + 1. You may copy and distribute verbatim copies of the Library\'s +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library.\n\n + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee.\n\n + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions:\n\n + +a) The modified work must itself be a software library.\n\n + +b) You must cause the files modified to carry prominent notices +stating that you changed the files and the date of any change.\n\n + +c) You must cause the whole of the work to be licensed at no +charge to all third parties under the terms of this License.\n\n + +d) If a facility in the modified Library refers to a function or a +table of data to be supplied by an application program that uses +the facility, other than as an argument passed when the facility +is invoked, then you must make a good faith effort to ensure that, +in the event an application does not supply such function or +table, the facility still operates, and performs whatever part of +its purpose remains meaningful.\n\n + +(For example, a function in a library to compute square roots has +a purpose that is entirely well-defined independent of the +application. Therefore, Subsection 2d requires that any +application-supplied function or table used by this function must +be optional: if the application does not supply it, the square +root function must still compute square roots.)\n\n + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it.\n\n + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library.\n\n + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License.\n\n + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices.\n\n + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy.\n\n + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library.\n\n + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange.\n\n + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code.\n\n + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a \"work that uses the Library\". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License.\n\n + + However, linking a \"work that uses the Library\" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a \"work that uses the +library\". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables.\n\n + + When a \"work that uses the Library\" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law.\n\n + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.)\n\n + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself.\n\n + + 6. As an exception to the Sections above, you may also combine or +link a \"work that uses the Library\" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer\'s own use and reverse +engineering for debugging such modifications.\n\n + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things:\n\n + +a) Accompany the work with the complete corresponding +machine-readable source code for the Library including whatever +changes were used in the work (which must be distributed under +Sections 1 and 2 above); and, if the work is an executable linked +with the Library, with the complete machine-readable \"work that +uses the Library\", as object code and/or source code, so that the +user can modify the Library and then relink to produce a modified +executable containing the modified Library. (It is understood +that the user who changes the contents of definitions files in the +Library will not necessarily be able to recompile the application +to use the modified definitions.)\n\n + +b) Use a suitable shared library mechanism for linking with the +Library. A suitable mechanism is one that (1) uses at run time a +copy of the library already present on the user\'s computer system, +rather than copying library functions into the executable, and (2) +will operate properly with a modified version of the library, if +the user installs one, as long as the modified version is +interface-compatible with the version that the work was made with.\n\n + +c) Accompany the work with a written offer, valid for at +least three years, to give the same user the materials +specified in Subsection 6a, above, for a charge no more +than the cost of performing this distribution.\n\n + +d) If distribution of the work is made by offering access to copy +from a designated place, offer equivalent access to copy the above +specified materials from the same place.\n\n + +e) Verify that the user has already received a copy of these +materials or that you have already sent this user a copy.\n\n + + For an executable, the required form of the \"work that uses the +Library\" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable.\n\n + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute.\n\n + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things:\n\n + +a) Accompany the combined library with a copy of the same work +based on the Library, uncombined with any other library +facilities. This must be distributed under the terms of the +Sections above.\n\n + +b) Give prominent notice with the combined library of the fact +that part of it is a work based on the Library, and explaining +where to find the accompanying uncombined form of the same work.\n\n + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance.\n\n + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it.\n\n + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients\' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License.\n\n + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library.\n\n + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances.\n\n + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice.\n\n + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License.\n\n + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License.\n\n + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns.\n\n + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version\", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation.\n\n + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally.\n\n + +NO WARRANTY\n\n + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + </string> + <string name="license_opus" translatable="false">Opus</string> + <string name="license_opus_description" translatable="false">Modern audio compression for the internet</string> + <string name="license_opus_link" translatable="false">https://github.com/xiph/opus</string> + <string name="license_opus_copyright" translatable="false">Copyright 2001–2011 Xiph.Org, Skype Limited, Octasic, Jean-Marc Valin, Timothy B. Terriberry, CSIRO, Gregory Maxwell, Mark Borgerding, Erik de Castro Lopo</string> + <string name="license_opus_text" translatable="false"> +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met:\n\n + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer.\n\n + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution.\n\n + +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission.\n\n + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n + +Opus is subject to the royalty-free patent licenses which are +specified at:\n\n + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ \n\n + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ \n\n + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ + </string> + <string name="license_sirit" translatable="false">Sirit</string> + <string name="license_sirit_description" translatable="false">A runtime SPIR-V assembler</string> + <string name="license_sirit_link" translatable="false">https://github.com/ReinUsesLisp/sirit</string> + <string name="license_sirit_copyright" translatable="false">Copyright © 2019, sirit All rights reserved.</string> + <string name="license_sirit_text" translatable="false"> +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met:\n +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer.\n +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution.\n +* Neither the name of the organization nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission.\n\n + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + </string> + <string name="license_adreno_tools" translatable="false">Adreno Tools</string> + <string name="license_adreno_tools_description" translatable="false">A library for applying rootless Adreno GPU driver modifications/replacements</string> + <string name="license_adreno_tools_link" translatable="false">https://github.com/bylaws/libadrenotools</string> + <string name="license_adreno_tools_copyright" translatable="false">Copyright © 2021, Billy Laws</string> + <string name="license_adreno_tools_text" translatable="false"> +BSD 2-Clause License\n\n + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met:\n\n + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer.\n\n + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution.\n\n + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + </string> + </resources> |