summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt54
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt10
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt36
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt34
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt70
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicenseBottomSheetDialogFragment.kt59
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt137
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/License.kt16
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/TaskViewModel.kt47
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt55
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt32
-rw-r--r--src/android/app/src/main/res/drawable/ic_firmware.xml10
-rw-r--r--src/android/app/src/main/res/drawable/ic_log.xml10
-rw-r--r--src/android/app/src/main/res/layout/dialog_license.xml64
-rw-r--r--src/android/app/src/main/res/layout/fragment_about.xml33
-rw-r--r--src/android/app/src/main/res/layout/fragment_licenses.xml30
-rw-r--r--src/android/app/src/main/res/navigation/home_navigation.xml11
-rw-r--r--src/android/app/src/main/res/values/strings.xml517
18 files changed, 1188 insertions, 37 deletions
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.adapters
5
6import android.view.LayoutInflater
7import android.view.View
8import android.view.ViewGroup
9import androidx.appcompat.app.AppCompatActivity
10import androidx.recyclerview.widget.RecyclerView
11import androidx.recyclerview.widget.RecyclerView.ViewHolder
12import org.yuzu.yuzu_emu.YuzuApplication
13import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
14import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
15import org.yuzu.yuzu_emu.model.License
16
17class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) :
18 RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(),
19 View.OnClickListener {
20 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder {
21 val binding =
22 ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
23 binding.root.setOnClickListener(this)
24 return LicenseViewHolder(binding)
25 }
26
27 override fun getItemCount(): Int = licenses.size
28
29 override fun onBindViewHolder(holder: LicenseViewHolder, position: Int) {
30 holder.bind(licenses[position])
31 }
32
33 override fun onClick(view: View) {
34 val license = (view.tag as LicenseViewHolder).license
35 LicenseBottomSheetDialogFragment.newInstance(license)
36 .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG)
37 }
38
39 inner class LicenseViewHolder(val binding: ListItemSettingBinding) : ViewHolder(binding.root) {
40 lateinit var license: License
41
42 init {
43 itemView.tag = this
44 }
45
46 fun bind(license: License) {
47 this.license = license
48
49 val context = YuzuApplication.appContext
50 binding.textSettingName.text = context.getString(license.titleId)
51 binding.textSettingDescription.text = context.getString(license.descriptionId)
52 }
53 }
54}
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
15import android.view.ViewGroup 15import android.view.ViewGroup
16import android.view.ViewGroup.MarginLayoutParams 16import android.view.ViewGroup.MarginLayoutParams
17import android.widget.Toast 17import android.widget.Toast
18import androidx.core.content.ContextCompat
19import androidx.core.view.ViewCompat 18import androidx.core.view.ViewCompat
20import androidx.core.view.WindowInsetsCompat 19import androidx.core.view.WindowInsetsCompat
21import androidx.core.view.updatePadding 20import androidx.core.view.updatePadding
22import androidx.fragment.app.Fragment 21import androidx.fragment.app.Fragment
23import androidx.fragment.app.activityViewModels 22import androidx.fragment.app.activityViewModels
24import androidx.navigation.fragment.findNavController 23import androidx.navigation.findNavController
25import com.google.android.material.transition.MaterialSharedAxis 24import com.google.android.material.transition.MaterialSharedAxis
26import org.yuzu.yuzu_emu.BuildConfig 25import org.yuzu.yuzu_emu.BuildConfig
27import org.yuzu.yuzu_emu.R 26import org.yuzu.yuzu_emu.R
@@ -38,6 +37,7 @@ class AboutFragment : Fragment() {
38 super.onCreate(savedInstanceState) 37 super.onCreate(savedInstanceState)
39 enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) 38 enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
40 returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) 39 returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
40 reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
41 } 41 }
42 42
43 override fun onCreateView( 43 override fun onCreateView(
@@ -54,7 +54,7 @@ class AboutFragment : Fragment() {
54 homeViewModel.setStatusBarShadeVisibility(visible = false) 54 homeViewModel.setStatusBarShadeVisibility(visible = false)
55 55
56 binding.toolbarAbout.setNavigationOnClickListener { 56 binding.toolbarAbout.setNavigationOnClickListener {
57 parentFragmentManager.primaryNavigationFragment?.findNavController()?.popBackStack() 57 binding.root.findNavController().popBackStack()
58 } 58 }
59 59
60 binding.imageLogo.setOnLongClickListener { 60 binding.imageLogo.setOnLongClickListener {
@@ -67,6 +67,10 @@ class AboutFragment : Fragment() {
67 } 67 }
68 68
69 binding.buttonContributors.setOnClickListener { openLink(getString(R.string.contributors_link)) } 69 binding.buttonContributors.setOnClickListener { openLink(getString(R.string.contributors_link)) }
70 binding.buttonLicenses.setOnClickListener {
71 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
72 binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment)
73 }
70 74
71 binding.textBuildHash.text = BuildConfig.GIT_HASH 75 binding.textBuildHash.text = BuildConfig.GIT_HASH
72 binding.buttonBuildHash.setOnClickListener { 76 binding.buttonBuildHash.setOnClickListener {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
index 67bcf8491..bdc337501 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
@@ -19,10 +19,10 @@ import androidx.appcompat.app.AppCompatActivity
19import androidx.core.app.ActivityCompat 19import androidx.core.app.ActivityCompat
20import androidx.core.app.NotificationCompat 20import androidx.core.app.NotificationCompat
21import androidx.core.app.NotificationManagerCompat 21import androidx.core.app.NotificationManagerCompat
22import androidx.core.content.ContextCompat
23import androidx.core.view.ViewCompat 22import androidx.core.view.ViewCompat
24import androidx.core.view.WindowInsetsCompat 23import androidx.core.view.WindowInsetsCompat
25import androidx.core.view.updatePadding 24import androidx.core.view.updatePadding
25import androidx.documentfile.provider.DocumentFile
26import androidx.fragment.app.Fragment 26import androidx.fragment.app.Fragment
27import androidx.fragment.app.activityViewModels 27import androidx.fragment.app.activityViewModels
28import androidx.navigation.fragment.findNavController 28import androidx.navigation.fragment.findNavController
@@ -40,6 +40,7 @@ import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
40import org.yuzu.yuzu_emu.model.HomeSetting 40import org.yuzu.yuzu_emu.model.HomeSetting
41import org.yuzu.yuzu_emu.model.HomeViewModel 41import org.yuzu.yuzu_emu.model.HomeViewModel
42import org.yuzu.yuzu_emu.ui.main.MainActivity 42import org.yuzu.yuzu_emu.ui.main.MainActivity
43import org.yuzu.yuzu_emu.utils.FileUtil
43import org.yuzu.yuzu_emu.utils.GpuDriverHelper 44import org.yuzu.yuzu_emu.utils.GpuDriverHelper
44 45
45class HomeSettingsFragment : Fragment() { 46class HomeSettingsFragment : Fragment() {
@@ -109,6 +110,16 @@ class HomeSettingsFragment : Fragment() {
109 R.drawable.ic_unlock 110 R.drawable.ic_unlock
110 ) { mainActivity.getProdKey.launch(arrayOf("*/*")) }, 111 ) { mainActivity.getProdKey.launch(arrayOf("*/*")) },
111 HomeSetting( 112 HomeSetting(
113 R.string.install_firmware,
114 R.string.install_firmware_description,
115 R.drawable.ic_firmware
116 ) { mainActivity.getFirmware.launch(arrayOf("application/zip")) },
117 HomeSetting(
118 R.string.share_log,
119 R.string.share_log_description,
120 R.drawable.ic_log
121 ) { shareLog() },
122 HomeSetting(
112 R.string.about, 123 R.string.about,
113 R.string.about_description, 124 R.string.about_description,
114 R.drawable.ic_info_outline 125 R.drawable.ic_info_outline
@@ -262,6 +273,29 @@ class HomeSettingsFragment : Fragment() {
262 .show() 273 .show()
263 } 274 }
264 275
276 private fun shareLog() {
277 val file = DocumentFile.fromSingleUri(
278 mainActivity,
279 DocumentsContract.buildDocumentUri(
280 DocumentProvider.AUTHORITY,
281 "${DocumentProvider.ROOT_ID}/log/yuzu_log.txt"
282 )
283 )!!
284 if (file.exists()) {
285 val intent = Intent(Intent.ACTION_SEND)
286 .setDataAndType(file.uri, FileUtil.TEXT_PLAIN)
287 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
288 .putExtra(Intent.EXTRA_STREAM, file.uri)
289 startActivity(Intent.createChooser(intent, getText(R.string.share_log)))
290 } else {
291 Toast.makeText(
292 requireContext(),
293 getText(R.string.share_log_missing),
294 Toast.LENGTH_SHORT
295 ).show()
296 }
297 }
298
265 private fun setInsets() = 299 private fun setInsets() =
266 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat -> 300 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat ->
267 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 301 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt
index 5f107b37d..36e63bb9e 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt
@@ -23,17 +23,14 @@ import org.yuzu.yuzu_emu.R
23import org.yuzu.yuzu_emu.YuzuApplication 23import org.yuzu.yuzu_emu.YuzuApplication
24import org.yuzu.yuzu_emu.features.DocumentProvider 24import org.yuzu.yuzu_emu.features.DocumentProvider
25import org.yuzu.yuzu_emu.getPublicFilesDir 25import org.yuzu.yuzu_emu.getPublicFilesDir
26import java.io.BufferedInputStream 26import org.yuzu.yuzu_emu.utils.FileUtil
27import java.io.BufferedOutputStream 27import java.io.BufferedOutputStream
28import java.io.File 28import java.io.File
29import java.io.FileOutputStream 29import java.io.FileOutputStream
30import java.io.FilenameFilter 30import java.io.FilenameFilter
31import java.io.IOException
32import java.io.InputStream
33import java.time.LocalDateTime 31import java.time.LocalDateTime
34import java.time.format.DateTimeFormatter 32import java.time.format.DateTimeFormatter
35import java.util.zip.ZipEntry 33import java.util.zip.ZipEntry
36import java.util.zip.ZipInputStream
37import java.util.zip.ZipOutputStream 34import java.util.zip.ZipOutputStream
38 35
39class ImportExportSavesFragment : DialogFragment() { 36class ImportExportSavesFragment : DialogFragment() {
@@ -125,33 +122,6 @@ class ImportExportSavesFragment : DialogFragment() {
125 } 122 }
126 123
127 /** 124 /**
128 * Extracts the save files located in the given zip file and copies them to the saves folder.
129 * @exception IOException if the file was being created outside of the target directory
130 */
131 private fun unzip(zipStream: InputStream, destDir: File): Boolean {
132 val zis = ZipInputStream(BufferedInputStream(zipStream))
133 var entry: ZipEntry? = zis.nextEntry
134 while (entry != null) {
135 val entryName = entry.name
136 val entryFile = File(destDir, entryName)
137 if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath + File.separator)) {
138 zis.close()
139 throw IOException("Entry is outside of the target dir: " + entryFile.name)
140 }
141 if (entry.isDirectory) {
142 entryFile.mkdirs()
143 } else {
144 entryFile.parentFile?.mkdirs()
145 entryFile.createNewFile()
146 entryFile.outputStream().use { fos -> zis.copyTo(fos) }
147 }
148 entry = zis.nextEntry
149 }
150 zis.close()
151 return true
152 }
153
154 /**
155 * Exports the save file located in the given folder path by creating a zip file and sharing it via intent. 125 * Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
156 */ 126 */
157 private fun exportSave() { 127 private fun exportSave() {
@@ -204,7 +174,7 @@ class ImportExportSavesFragment : DialogFragment() {
204 174
205 try { 175 try {
206 CoroutineScope(Dispatchers.IO).launch { 176 CoroutineScope(Dispatchers.IO).launch {
207 unzip(inputZip, cacheSaveDir) 177 FileUtil.unzip(inputZip, cacheSaveDir)
208 cacheSaveDir.list(filterTitleId)?.forEach { savePath -> 178 cacheSaveDir.list(filterTitleId)?.forEach { savePath ->
209 File(savesFolder, savePath).deleteRecursively() 179 File(savesFolder, savePath).deleteRecursively()
210 File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true) 180 File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt
new file mode 100644
index 000000000..c7880d8cc
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt
@@ -0,0 +1,70 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.fragments
5
6import android.app.Dialog
7import android.os.Bundle
8import android.widget.Toast
9import androidx.appcompat.app.AppCompatActivity
10import androidx.fragment.app.DialogFragment
11import androidx.fragment.app.activityViewModels
12import androidx.lifecycle.ViewModelProvider
13import com.google.android.material.dialog.MaterialAlertDialogBuilder
14import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
15import org.yuzu.yuzu_emu.model.TaskViewModel
16
17
18class IndeterminateProgressDialogFragment : DialogFragment() {
19 private val taskViewModel: TaskViewModel by activityViewModels()
20
21 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
22 val titleId = requireArguments().getInt(TITLE)
23
24 val progressBinding = DialogProgressBarBinding.inflate(layoutInflater)
25 progressBinding.progressBar.isIndeterminate = true
26 val dialog = MaterialAlertDialogBuilder(requireContext())
27 .setTitle(titleId)
28 .setView(progressBinding.root)
29 .create()
30 dialog.setCanceledOnTouchOutside(false)
31
32 taskViewModel.isComplete.observe(this) { complete ->
33 if (complete) {
34 dialog.dismiss()
35 when (val result = taskViewModel.result.value) {
36 is String -> Toast.makeText(requireContext(), result, Toast.LENGTH_LONG).show()
37 is MessageDialogFragment -> result.show(
38 parentFragmentManager,
39 MessageDialogFragment.TAG
40 )
41 }
42 taskViewModel.clear()
43 }
44 }
45
46 if (taskViewModel.isRunning.value == false) {
47 taskViewModel.runTask()
48 }
49 return dialog
50 }
51
52 companion object {
53 const val TAG = "IndeterminateProgressDialogFragment"
54
55 private const val TITLE = "Title"
56
57 fun newInstance(
58 activity: AppCompatActivity,
59 titleId: Int,
60 task: () -> Any
61 ): IndeterminateProgressDialogFragment {
62 val dialog = IndeterminateProgressDialogFragment()
63 val args = Bundle()
64 ViewModelProvider(activity)[TaskViewModel::class.java].task = task
65 args.putInt(TITLE, titleId)
66 dialog.arguments = args
67 return dialog
68 }
69 }
70}
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.fragments
5
6import android.os.Bundle
7import android.view.LayoutInflater
8import android.view.View
9import android.view.ViewGroup
10import com.google.android.material.bottomsheet.BottomSheetBehavior
11import com.google.android.material.bottomsheet.BottomSheetDialogFragment
12import org.yuzu.yuzu_emu.databinding.DialogLicenseBinding
13import org.yuzu.yuzu_emu.model.License
14import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable
15
16class LicenseBottomSheetDialogFragment : BottomSheetDialogFragment() {
17 private var _binding: DialogLicenseBinding? = null
18 private val binding get() = _binding!!
19
20 override fun onCreateView(
21 inflater: LayoutInflater,
22 container: ViewGroup?,
23 savedInstanceState: Bundle?
24 ): View {
25 _binding = DialogLicenseBinding.inflate(layoutInflater)
26 return binding.root
27 }
28
29 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
30 super.onViewCreated(view, savedInstanceState)
31 BottomSheetBehavior.from<View>(view.parent as View).state =
32 BottomSheetBehavior.STATE_HALF_EXPANDED
33
34 val license = requireArguments().parcelable<License>(LICENSE)!!
35
36 binding.apply {
37 textTitle.setText(license.titleId)
38 textLink.setText(license.linkId)
39 textCopyright.setText(license.copyrightId)
40 textLicense.setText(license.licenseId)
41 }
42 }
43
44 companion object {
45 const val TAG = "LicenseBottomSheetDialogFragment"
46
47 const val LICENSE = "License"
48
49 fun newInstance(
50 license: License
51 ): LicenseBottomSheetDialogFragment {
52 val dialog = LicenseBottomSheetDialogFragment()
53 val bundle = Bundle()
54 bundle.putParcelable(LICENSE, license)
55 dialog.arguments = bundle
56 return dialog
57 }
58 }
59}
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.fragments
5
6import android.os.Bundle
7import android.view.LayoutInflater
8import android.view.View
9import android.view.ViewGroup
10import android.view.ViewGroup.MarginLayoutParams
11import androidx.appcompat.app.AppCompatActivity
12import androidx.core.view.ViewCompat
13import androidx.core.view.WindowInsetsCompat
14import androidx.core.view.updatePadding
15import androidx.fragment.app.Fragment
16import androidx.fragment.app.activityViewModels
17import androidx.navigation.findNavController
18import androidx.recyclerview.widget.LinearLayoutManager
19import com.google.android.material.transition.MaterialSharedAxis
20import org.yuzu.yuzu_emu.R
21import org.yuzu.yuzu_emu.adapters.LicenseAdapter
22import org.yuzu.yuzu_emu.databinding.FragmentLicensesBinding
23import org.yuzu.yuzu_emu.model.HomeViewModel
24import org.yuzu.yuzu_emu.model.License
25
26class LicensesFragment : Fragment() {
27 private var _binding: FragmentLicensesBinding? = null
28 private val binding get() = _binding!!
29
30 private val homeViewModel: HomeViewModel by activityViewModels()
31
32 override fun onCreate(savedInstanceState: Bundle?) {
33 super.onCreate(savedInstanceState)
34 enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
35 returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
36 }
37
38 override fun onCreateView(
39 inflater: LayoutInflater,
40 container: ViewGroup?,
41 savedInstanceState: Bundle?
42 ): View {
43 _binding = FragmentLicensesBinding.inflate(layoutInflater)
44 return binding.root
45 }
46
47 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
48 homeViewModel.setNavigationVisibility(visible = false, animated = true)
49 homeViewModel.setStatusBarShadeVisibility(visible = false)
50
51 binding.toolbarLicenses.setNavigationOnClickListener {
52 binding.root.findNavController().popBackStack()
53 }
54
55 val licenses = listOf(
56 License(
57 R.string.license_fidelityfx_fsr,
58 R.string.license_fidelityfx_fsr_description,
59 R.string.license_fidelityfx_fsr_link,
60 R.string.license_fidelityfx_fsr_copyright,
61 R.string.license_fidelityfx_fsr_text
62 ),
63 License(
64 R.string.license_cubeb,
65 R.string.license_cubeb_description,
66 R.string.license_cubeb_link,
67 R.string.license_cubeb_copyright,
68 R.string.license_cubeb_text
69 ),
70 License(
71 R.string.license_dynarmic,
72 R.string.license_dynarmic_description,
73 R.string.license_dynarmic_link,
74 R.string.license_dynarmic_copyright,
75 R.string.license_dynarmic_text
76 ),
77 License(
78 R.string.license_ffmpeg,
79 R.string.license_ffmpeg_description,
80 R.string.license_ffmpeg_link,
81 R.string.license_ffmpeg_copyright,
82 R.string.license_ffmpeg_text
83 ),
84 License(
85 R.string.license_opus,
86 R.string.license_opus_description,
87 R.string.license_opus_link,
88 R.string.license_opus_copyright,
89 R.string.license_opus_text
90 ),
91 License(
92 R.string.license_sirit,
93 R.string.license_sirit_description,
94 R.string.license_sirit_link,
95 R.string.license_sirit_copyright,
96 R.string.license_sirit_text
97 ),
98 License(
99 R.string.license_adreno_tools,
100 R.string.license_adreno_tools_description,
101 R.string.license_adreno_tools_link,
102 R.string.license_adreno_tools_copyright,
103 R.string.license_adreno_tools_text
104 )
105 )
106
107 binding.listLicenses.apply {
108 layoutManager = LinearLayoutManager(requireContext())
109 adapter = LicenseAdapter(requireActivity() as AppCompatActivity, licenses)
110 }
111
112 setInsets()
113 }
114
115 private fun setInsets() =
116 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat ->
117 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
118 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
119
120 val leftInsets = barInsets.left + cutoutInsets.left
121 val rightInsets = barInsets.right + cutoutInsets.right
122
123 val mlpAppBar = binding.appbarLicenses.layoutParams as MarginLayoutParams
124 mlpAppBar.leftMargin = leftInsets
125 mlpAppBar.rightMargin = rightInsets
126 binding.appbarLicenses.layoutParams = mlpAppBar
127
128 val mlpScrollAbout = binding.listLicenses.layoutParams as MarginLayoutParams
129 mlpScrollAbout.leftMargin = leftInsets
130 mlpScrollAbout.rightMargin = rightInsets
131 binding.listLicenses.layoutParams = mlpScrollAbout
132
133 binding.listLicenses.updatePadding(bottom = barInsets.bottom)
134
135 windowInsets
136 }
137}
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.model
5
6import android.os.Parcelable
7import kotlinx.parcelize.Parcelize
8
9@Parcelize
10data class License(
11 val titleId: Int,
12 val descriptionId: Int,
13 val linkId: Int,
14 val copyrightId: Int,
15 val licenseId: Int
16) : Parcelable
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/TaskViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/TaskViewModel.kt
new file mode 100644
index 000000000..27ea725a5
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/TaskViewModel.kt
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.model
5
6import androidx.lifecycle.LiveData
7import androidx.lifecycle.MutableLiveData
8import androidx.lifecycle.ViewModel
9import androidx.lifecycle.viewModelScope
10import kotlinx.coroutines.Dispatchers
11import kotlinx.coroutines.launch
12
13class TaskViewModel : ViewModel() {
14 private val _result = MutableLiveData<Any>()
15 val result: LiveData<Any> = _result
16
17 private val _isComplete = MutableLiveData<Boolean>()
18 val isComplete: LiveData<Boolean> = _isComplete
19
20 private val _isRunning = MutableLiveData<Boolean>()
21 val isRunning: LiveData<Boolean> = _isRunning
22
23 lateinit var task: () -> Any
24
25 init {
26 clear()
27 }
28
29 fun clear() {
30 _result.value = Any()
31 _isComplete.value = false
32 _isRunning.value = false
33 }
34
35 fun runTask() {
36 if (_isRunning.value == true) {
37 return
38 }
39 _isRunning.value = true
40
41 viewModelScope.launch(Dispatchers.IO) {
42 val res = task()
43 _result.postValue(res)
44 _isComplete.postValue(true)
45 }
46 }
47}
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 134085210..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
@@ -38,10 +38,13 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings
38import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel 38import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
39import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity 39import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
40import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 40import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
41import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
41import org.yuzu.yuzu_emu.fragments.MessageDialogFragment 42import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
42import org.yuzu.yuzu_emu.model.GamesViewModel 43import org.yuzu.yuzu_emu.model.GamesViewModel
43import org.yuzu.yuzu_emu.model.HomeViewModel 44import org.yuzu.yuzu_emu.model.HomeViewModel
44import org.yuzu.yuzu_emu.utils.* 45import org.yuzu.yuzu_emu.utils.*
46import java.io.File
47import java.io.FilenameFilter
45import java.io.IOException 48import java.io.IOException
46 49
47class MainActivity : AppCompatActivity(), ThemeProvider { 50class MainActivity : AppCompatActivity(), ThemeProvider {
@@ -319,6 +322,58 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
319 } 322 }
320 } 323 }
321 324
325 val getFirmware =
326 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
327 if (result == null)
328 return@registerForActivityResult
329
330 val inputZip = contentResolver.openInputStream(result)
331 if (inputZip == null) {
332 Toast.makeText(
333 applicationContext,
334 getString(R.string.fatal_error),
335 Toast.LENGTH_LONG
336 ).show()
337 return@registerForActivityResult
338 }
339
340 val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") }
341
342 val firmwarePath =
343 File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
344 val cacheFirmwareDir = File("${cacheDir.path}/registered/")
345
346 val task: () -> Any = {
347 var messageToShow: Any
348 try {
349 FileUtil.unzip(inputZip, cacheFirmwareDir)
350 val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1
351 val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2
352 messageToShow = if (unfilteredNumOfFiles != filteredNumOfFiles) {
353 MessageDialogFragment.newInstance(
354 R.string.firmware_installed_failure,
355 R.string.firmware_installed_failure_description
356 )
357 } else {
358 firmwarePath.deleteRecursively()
359 cacheFirmwareDir.copyRecursively(firmwarePath, true)
360 getString(R.string.save_file_imported_success)
361 }
362 } catch (e: Exception) {
363 messageToShow = getString(R.string.fatal_error)
364 } finally {
365 cacheFirmwareDir.deleteRecursively()
366 }
367 messageToShow
368 }
369
370 IndeterminateProgressDialogFragment.newInstance(
371 this,
372 R.string.firmware_installing,
373 task
374 ).show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
375 }
376
322 val getAmiiboKey = 377 val getAmiiboKey =
323 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> 378 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
324 if (result == null) 379 if (result == null)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
index 0a7b323b1..593dad8d3 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
@@ -9,10 +9,14 @@ import android.net.Uri
9import android.provider.DocumentsContract 9import android.provider.DocumentsContract
10import androidx.documentfile.provider.DocumentFile 10import androidx.documentfile.provider.DocumentFile
11import org.yuzu.yuzu_emu.model.MinimalDocumentFile 11import org.yuzu.yuzu_emu.model.MinimalDocumentFile
12import java.io.BufferedInputStream
13import java.io.File
12import java.io.FileOutputStream 14import java.io.FileOutputStream
13import java.io.IOException 15import java.io.IOException
14import java.io.InputStream 16import java.io.InputStream
15import java.net.URLDecoder 17import java.net.URLDecoder
18import java.util.zip.ZipEntry
19import java.util.zip.ZipInputStream
16 20
17object FileUtil { 21object FileUtil {
18 const val PATH_TREE = "tree" 22 const val PATH_TREE = "tree"
@@ -276,6 +280,34 @@ object FileUtil {
276 return false 280 return false
277 } 281 }
278 282
283 /**
284 * Extracts the given zip file into the given directory.
285 * @exception IOException if the file was being created outside of the target directory
286 */
287 @Throws(SecurityException::class)
288 fun unzip(zipStream: InputStream, destDir: File): Boolean {
289 ZipInputStream(BufferedInputStream(zipStream)).use { zis ->
290 var entry: ZipEntry? = zis.nextEntry
291 while (entry != null) {
292 val entryName = entry.name
293 val entryFile = File(destDir, entryName)
294 if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath + File.separator)) {
295 throw SecurityException("Entry is outside of the target dir: " + entryFile.name)
296 }
297 if (entry.isDirectory) {
298 entryFile.mkdirs()
299 } else {
300 entryFile.parentFile?.mkdirs()
301 entryFile.createNewFile()
302 entryFile.outputStream().use { fos -> zis.copyTo(fos) }
303 }
304 entry = zis.nextEntry
305 }
306 }
307
308 return true
309 }
310
279 fun isRootTreeUri(uri: Uri): Boolean { 311 fun isRootTreeUri(uri: Uri): Boolean {
280 val paths = uri.pathSegments 312 val paths = uri.pathSegments
281 return paths.size == 2 && PATH_TREE == paths[0] 313 return paths.size == 2 && PATH_TREE == paths[0]
diff --git a/src/android/app/src/main/res/drawable/ic_firmware.xml b/src/android/app/src/main/res/drawable/ic_firmware.xml
new file mode 100644
index 000000000..61f3485e4
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_firmware.xml
@@ -0,0 +1,10 @@
1<vector xmlns:android="http://schemas.android.com/apk/res/android"
2 android:width="24dp"
3 android:height="24dp"
4 android:viewportWidth="960"
5 android:viewportHeight="960"
6 android:tint="?attr/colorControlNormal">
7 <path
8 android:fillColor="@android:color/white"
9 android:pathData="M160,840Q127,840 103.5,816.5Q80,793 80,760L80,200Q80,167 103.5,143.5Q127,120 160,120L720,120Q753,120 776.5,143.5Q800,167 800,200L800,280L840,280Q857,280 868.5,291.5Q880,303 880,320Q880,337 868.5,348.5Q857,360 840,360L800,360L800,440L840,440Q857,440 868.5,451.5Q880,463 880,480Q880,497 868.5,508.5Q857,520 840,520L800,520L800,600L840,600Q857,600 868.5,611.5Q880,623 880,640Q880,657 868.5,668.5Q857,680 840,680L800,680L800,760Q800,793 776.5,816.5Q753,840 720,840L160,840ZM160,760L720,760Q720,760 720,760Q720,760 720,760L720,200Q720,200 720,200Q720,200 720,200L160,200Q160,200 160,200Q160,200 160,200L160,760Q160,760 160,760Q160,760 160,760ZM280,680L400,680Q417,680 428.5,668.5Q440,657 440,640L440,560Q440,543 428.5,531.5Q417,520 400,520L280,520Q263,520 251.5,531.5Q240,543 240,560L240,640Q240,657 251.5,668.5Q263,680 280,680ZM520,400L600,400Q617,400 628.5,388.5Q640,377 640,360L640,320Q640,303 628.5,291.5Q617,280 600,280L520,280Q503,280 491.5,291.5Q480,303 480,320L480,360Q480,377 491.5,388.5Q503,400 520,400ZM280,480L400,480Q417,480 428.5,468.5Q440,457 440,440L440,320Q440,303 428.5,291.5Q417,280 400,280L280,280Q263,280 251.5,291.5Q240,303 240,320L240,440Q240,457 251.5,468.5Q263,480 280,480ZM520,680L600,680Q617,680 628.5,668.5Q640,657 640,640L640,480Q640,463 628.5,451.5Q617,440 600,440L520,440Q503,440 491.5,451.5Q480,463 480,480L480,640Q480,657 491.5,668.5Q503,680 520,680ZM160,200L160,200Q160,200 160,200Q160,200 160,200L160,760Q160,760 160,760Q160,760 160,760L160,760Q160,760 160,760Q160,760 160,760L160,200Q160,200 160,200Q160,200 160,200Z"/>
10</vector>
diff --git a/src/android/app/src/main/res/drawable/ic_log.xml b/src/android/app/src/main/res/drawable/ic_log.xml
new file mode 100644
index 000000000..f55b9ad85
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_log.xml
@@ -0,0 +1,10 @@
1<vector xmlns:android="http://schemas.android.com/apk/res/android"
2 android:width="24dp"
3 android:height="24dp"
4 android:viewportWidth="960"
5 android:viewportHeight="960"
6 android:tint="?attr/colorControlNormal">
7 <path
8 android:fillColor="@android:color/white"
9 android:pathData="M360,720L600,720Q617,720 628.5,708.5Q640,697 640,680Q640,663 628.5,651.5Q617,640 600,640L360,640Q343,640 331.5,651.5Q320,663 320,680Q320,697 331.5,708.5Q343,720 360,720ZM360,560L600,560Q617,560 628.5,548.5Q640,537 640,520Q640,503 628.5,491.5Q617,480 600,480L360,480Q343,480 331.5,491.5Q320,503 320,520Q320,537 331.5,548.5Q343,560 360,560ZM240,880Q207,880 183.5,856.5Q160,833 160,800L160,160Q160,127 183.5,103.5Q207,80 240,80L527,80Q543,80 557.5,86Q572,92 583,103L777,297Q788,308 794,322.5Q800,337 800,353L800,800Q800,833 776.5,856.5Q753,880 720,880L240,880ZM520,320L520,160L240,160Q240,160 240,160Q240,160 240,160L240,800Q240,800 240,800Q240,800 240,800L720,800Q720,800 720,800Q720,800 720,800L720,360L560,360Q543,360 531.5,348.5Q520,337 520,320ZM240,160L240,160L240,320Q240,337 240,348.5Q240,360 240,360L240,360L240,160L240,320Q240,337 240,348.5Q240,360 240,360L240,360L240,800Q240,800 240,800Q240,800 240,800L240,800Q240,800 240,800Q240,800 240,800L240,160Q240,160 240,160Q240,160 240,160Z"/>
10</vector>
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 @@
1<?xml version="1.0" encoding="utf-8"?>
2<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 xmlns:tools="http://schemas.android.com/tools">
6
7 <androidx.core.widget.NestedScrollView
8 android:layout_width="match_parent"
9 android:layout_height="wrap_content">
10
11 <LinearLayout
12 android:layout_width="match_parent"
13 android:layout_height="wrap_content"
14 android:orientation="vertical"
15 android:layout_marginHorizontal="16dp">
16
17 <com.google.android.material.bottomsheet.BottomSheetDragHandleView
18 android:layout_width="wrap_content"
19 android:layout_height="wrap_content"
20 android:layout_gravity="center_horizontal"/>
21
22 <com.google.android.material.textview.MaterialTextView
23 style="@style/TextAppearance.Material3.HeadlineLarge"
24 android:id="@+id/text_title"
25 android:layout_width="match_parent"
26 android:layout_height="wrap_content"
27 android:gravity="center"
28 tools:text="@string/license_adreno_tools" />
29
30 <com.google.android.material.textview.MaterialTextView
31 style="@style/TextAppearance.Material3.BodyLarge"
32 android:id="@+id/text_link"
33 android:layout_width="match_parent"
34 android:layout_height="wrap_content"
35 android:gravity="center"
36 android:layout_marginTop="16dp"
37 android:autoLink="all"
38 tools:text="@string/license_adreno_tools_link" />
39
40 <com.google.android.material.textview.MaterialTextView
41 style="@style/TextAppearance.Material3.BodyLarge"
42 android:id="@+id/text_copyright"
43 android:layout_width="match_parent"
44 android:layout_height="wrap_content"
45 android:gravity="center"
46 android:layout_marginTop="16dp"
47 android:textStyle="bold"
48 tools:text="@string/license_adreno_tools_copyright" />
49
50 <com.google.android.material.textview.MaterialTextView
51 style="@style/TextAppearance.Material3.BodyMedium"
52 android:id="@+id/text_license"
53 android:layout_width="match_parent"
54 android:layout_height="wrap_content"
55 android:layout_gravity="center"
56 android:layout_marginVertical="16dp"
57 android:autoLink="all"
58 tools:text="@string/license_adreno_tools_text" />
59
60 </LinearLayout>
61
62 </androidx.core.widget.NestedScrollView>
63
64</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 @@
115 android:layout_marginHorizontal="20dp" /> 115 android:layout_marginHorizontal="20dp" />
116 116
117 <LinearLayout 117 <LinearLayout
118 android:id="@+id/button_licenses"
119 android:layout_width="match_parent"
120 android:layout_height="wrap_content"
121 android:paddingVertical="16dp"
122 android:paddingHorizontal="16dp"
123 android:background="?attr/selectableItemBackground"
124 android:orientation="vertical">
125
126 <com.google.android.material.textview.MaterialTextView
127 style="@style/TextAppearance.Material3.TitleMedium"
128 android:layout_width="match_parent"
129 android:layout_height="wrap_content"
130 android:layout_marginHorizontal="24dp"
131 android:textAlignment="viewStart"
132 android:text="@string/licenses" />
133
134 <com.google.android.material.textview.MaterialTextView
135 style="@style/TextAppearance.Material3.BodyMedium"
136 android:layout_width="match_parent"
137 android:layout_height="wrap_content"
138 android:layout_marginHorizontal="24dp"
139 android:layout_marginTop="6dp"
140 android:textAlignment="viewStart"
141 android:text="@string/licenses_description" />
142
143 </LinearLayout>
144
145 <com.google.android.material.divider.MaterialDivider
146 android:layout_width="match_parent"
147 android:layout_height="wrap_content"
148 android:layout_marginHorizontal="20dp" />
149
150 <LinearLayout
118 android:id="@+id/button_build_hash" 151 android:id="@+id/button_build_hash"
119 android:layout_width="match_parent" 152 android:layout_width="match_parent"
120 android:layout_height="wrap_content" 153 android:layout_height="wrap_content"
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 @@
1<?xml version="1.0" encoding="utf-8"?>
2<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 android:id="@+id/coordinator_licenses"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 android:background="?attr/colorSurface">
8
9 <com.google.android.material.appbar.AppBarLayout
10 android:id="@+id/appbar_licenses"
11 android:layout_width="match_parent"
12 android:layout_height="wrap_content"
13 android:fitsSystemWindows="true">
14
15 <com.google.android.material.appbar.MaterialToolbar
16 android:id="@+id/toolbar_licenses"
17 android:layout_width="match_parent"
18 android:layout_height="?attr/actionBarSize"
19 app:title="@string/licenses"
20 app:navigationIcon="@drawable/ic_back" />
21
22 </com.google.android.material.appbar.AppBarLayout>
23
24 <androidx.recyclerview.widget.RecyclerView
25 android:id="@+id/list_licenses"
26 android:layout_width="match_parent"
27 android:layout_height="match_parent"
28 app:layout_behavior="@string/appbar_scrolling_view_behavior" />
29
30</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 @@
40 <fragment 40 <fragment
41 android:id="@+id/aboutFragment" 41 android:id="@+id/aboutFragment"
42 android:name="org.yuzu.yuzu_emu.fragments.AboutFragment" 42 android:name="org.yuzu.yuzu_emu.fragments.AboutFragment"
43 android:label="AboutFragment" /> 43 android:label="AboutFragment" >
44 <action
45 android:id="@+id/action_aboutFragment_to_licensesFragment"
46 app:destination="@id/licensesFragment" />
47 </fragment>
44 48
45 <fragment 49 <fragment
46 android:id="@+id/earlyAccessFragment" 50 android:id="@+id/earlyAccessFragment"
47 android:name="org.yuzu.yuzu_emu.fragments.EarlyAccessFragment" 51 android:name="org.yuzu.yuzu_emu.fragments.EarlyAccessFragment"
48 android:label="EarlyAccessFragment" /> 52 android:label="EarlyAccessFragment" />
49 53
54 <fragment
55 android:id="@+id/licensesFragment"
56 android:name="org.yuzu.yuzu_emu.fragments.LicensesFragment"
57 android:label="LicensesFragment" />
58
50</navigation> 59</navigation>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index f9b759532..0ae69afb4 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -96,6 +96,15 @@
96 <string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string> 96 <string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string>
97 <string name="import_saves">Import</string> 97 <string name="import_saves">Import</string>
98 <string name="export_saves">Export</string> 98 <string name="export_saves">Export</string>
99 <string name="install_firmware">Install firmware</string>
100 <string name="install_firmware_description">Firmware must be in a ZIP archive and is needed to boot some games</string>
101 <string name="firmware_installing">Installing firmware</string>
102 <string name="firmware_installed_success">Firmware installed successfully</string>
103 <string name="firmware_installed_failure">Firmware installation failed</string>
104 <string name="firmware_installed_failure_description">Verify that the ZIP contains valid firmware and try again.</string>
105 <string name="share_log">Share debug logs</string>
106 <string name="share_log_description">Share yuzu\'s log file to debug issues</string>
107 <string name="share_log_missing">No log file found</string>
99 108
100 <!-- About screen strings --> 109 <!-- About screen strings -->
101 <string name="gaia_is_not_real">Gaia isn\'t real</string> 110 <string name="gaia_is_not_real">Gaia isn\'t real</string>
@@ -104,6 +113,7 @@
104 <string name="contributors">Contributors</string> 113 <string name="contributors">Contributors</string>
105 <string name="contributors_description">Made with \u2764 from the yuzu team</string> 114 <string name="contributors_description">Made with \u2764 from the yuzu team</string>
106 <string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string> 115 <string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string>
116 <string name="licenses_description">Projects that make yuzu for Android possible</string>
107 <string name="build">Build</string> 117 <string name="build">Build</string>
108 <string name="support_link">https://discord.gg/u77vRWY</string> 118 <string name="support_link">https://discord.gg/u77vRWY</string>
109 <string name="website_link">https://yuzu-emu.org/</string> 119 <string name="website_link">https://yuzu-emu.org/</string>
@@ -346,4 +356,511 @@
346 <string name="use_black_backgrounds">Black backgrounds</string> 356 <string name="use_black_backgrounds">Black backgrounds</string>
347 <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string> 357 <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
348 358
359 <!-- Licenses screen strings -->
360 <string name="licenses">Licenses</string>
361 <string name="license_fidelityfx_fsr" translatable="false">FidelityFX-FSR</string>
362 <string name="license_fidelityfx_fsr_description">High-quality upscaling from AMD</string>
363 <string name="license_fidelityfx_fsr_link" translatable="false">https://github.com/GPUOpen-Effects/FidelityFX-FSR</string>
364 <string name="license_fidelityfx_fsr_copyright" translatable="false">Copyright © 2021 Advanced Micro Devices, Inc.</string>
365 <string name="license_fidelityfx_fsr_text" translatable="false">
366Permission is hereby granted, free of charge, to any person obtaining a copy
367of this software and associated documentation files (the \"Software"), to deal
368in the Software without restriction, including without limitation the rights
369to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
370copies of the Software, and to permit persons to whom the Software is
371furnished to do so, subject to the following conditions:\n\n
372
373The above copyright notice and this permission notice shall be included in
374all copies or substantial portions of the Software.\n\n
375
376THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
377IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
378FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
379AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
380LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
381OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
382THE SOFTWARE.
383 </string>
384 <string name="license_cubeb" translatable="false">cubeb</string>
385 <string name="license_cubeb_description" translatable="false">Cross platform audio library</string>
386 <string name="license_cubeb_link" translatable="false">https://github.com/mozilla/cubeb</string>
387 <string name="license_cubeb_copyright" translatable="false">Copyright © 2011 Mozilla Foundation</string>
388 <string name="license_cubeb_text" translatable="false">
389Permission to use, copy, modify, and distribute this software for any
390purpose with or without fee is hereby granted, provided that the above
391copyright notice and this permission notice appear in all copies.\n\n
392
393THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
394WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
395MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
396ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
397WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
398ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
399OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
400 </string>
401 <string name="license_dynarmic" translatable="false">Dynarmic</string>
402 <string name="license_dynarmic_description" translatable="false">An ARM dynamic recompiler</string>
403 <string name="license_dynarmic_link" translatable="false">https://github.com/merryhime/dynarmic</string>
404 <string name="license_dynarmic_copyright" translatable="false">Copyright © 2017 merryhime</string>
405 <string name="license_dynarmic_text" translatable="false">
406Permission to use, copy, modify, and/or distribute this software for
407any purpose with or without fee is hereby granted.\n\n
408
409THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
410WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
411MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
412ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
413WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
414AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
415OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
416 </string>
417 <string name="license_ffmpeg" translatable="false">FFmpeg</string>
418 <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>
419 <string name="license_ffmpeg_link" translatable="false">https://github.com/FFmpeg/FFmpeg</string>
420 <string name="license_ffmpeg_copyright" translatable="false">Copyright © 1991, 1999 Free Software Foundation, Inc.</string>
421 <string name="license_ffmpeg_text" translatable="false">
422GNU LESSER GENERAL PUBLIC LICENSE\n
423TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n
424
425 0. This License Agreement applies to any software library or other
426program which contains a notice placed by the copyright holder or
427other authorized party saying it may be distributed under the terms of
428this Lesser General Public License (also called \"this License\").
429Each licensee is addressed as \"you\".\n\n
430
431 A \"library\" means a collection of software functions and/or data
432prepared so as to be conveniently linked with application programs
433(which use some of those functions and data) to form executables.\n\n
434
435 The \"Library\", below, refers to any such software library or work
436which has been distributed under these terms. A \"work based on the
437Library\" means either the Library or any derivative work under
438copyright law: that is to say, a work containing the Library or a
439portion of it, either verbatim or with modifications and/or translated
440straightforwardly into another language. (Hereinafter, translation is
441included without limitation in the term \"modification\".)\n\n
442
443 \"Source code\" for a work means the preferred form of the work for
444making modifications to it. For a library, complete source code means
445all the source code for all modules it contains, plus any associated
446interface definition files, plus the scripts used to control compilation
447and installation of the library.\n\n
448
449 Activities other than copying, distribution and modification are not
450covered by this License; they are outside its scope. The act of
451running a program using the Library is not restricted, and output from
452such a program is covered only if its contents constitute a work based
453on the Library (independent of the use of the Library in a tool for
454writing it). Whether that is true depends on what the Library does
455and what the program that uses the Library does.\n\n
456
457 1. You may copy and distribute verbatim copies of the Library\'s
458complete source code as you receive it, in any medium, provided that
459you conspicuously and appropriately publish on each copy an
460appropriate copyright notice and disclaimer of warranty; keep intact
461all the notices that refer to this License and to the absence of any
462warranty; and distribute a copy of this License along with the
463Library.\n\n
464
465 You may charge a fee for the physical act of transferring a copy,
466and you may at your option offer warranty protection in exchange for a
467fee.\n\n
468
469 2. You may modify your copy or copies of the Library or any portion
470of it, thus forming a work based on the Library, and copy and
471distribute such modifications or work under the terms of Section 1
472above, provided that you also meet all of these conditions:\n\n
473
474a) The modified work must itself be a software library.\n\n
475
476b) You must cause the files modified to carry prominent notices
477stating that you changed the files and the date of any change.\n\n
478
479c) You must cause the whole of the work to be licensed at no
480charge to all third parties under the terms of this License.\n\n
481
482d) If a facility in the modified Library refers to a function or a
483table of data to be supplied by an application program that uses
484the facility, other than as an argument passed when the facility
485is invoked, then you must make a good faith effort to ensure that,
486in the event an application does not supply such function or
487table, the facility still operates, and performs whatever part of
488its purpose remains meaningful.\n\n
489
490(For example, a function in a library to compute square roots has
491a purpose that is entirely well-defined independent of the
492application. Therefore, Subsection 2d requires that any
493application-supplied function or table used by this function must
494be optional: if the application does not supply it, the square
495root function must still compute square roots.)\n\n
496
497These requirements apply to the modified work as a whole. If
498identifiable sections of that work are not derived from the Library,
499and can be reasonably considered independent and separate works in
500themselves, then this License, and its terms, do not apply to those
501sections when you distribute them as separate works. But when you
502distribute the same sections as part of a whole which is a work based
503on the Library, the distribution of the whole must be on the terms of
504this License, whose permissions for other licensees extend to the
505entire whole, and thus to each and every part regardless of who wrote
506it.\n\n
507
508Thus, it is not the intent of this section to claim rights or contest
509your rights to work written entirely by you; rather, the intent is to
510exercise the right to control the distribution of derivative or
511collective works based on the Library.\n\n
512
513In addition, mere aggregation of another work not based on the Library
514with the Library (or with a work based on the Library) on a volume of
515a storage or distribution medium does not bring the other work under
516the scope of this License.\n\n
517
518 3. You may opt to apply the terms of the ordinary GNU General Public
519License instead of this License to a given copy of the Library. To do
520this, you must alter all the notices that refer to this License, so
521that they refer to the ordinary GNU General Public License, version 2,
522instead of to this License. (If a newer version than version 2 of the
523ordinary GNU General Public License has appeared, then you can specify
524that version instead if you wish.) Do not make any other change in
525these notices.\n\n
526
527 Once this change is made in a given copy, it is irreversible for
528that copy, so the ordinary GNU General Public License applies to all
529subsequent copies and derivative works made from that copy.\n\n
530
531 This option is useful when you wish to copy part of the code of
532the Library into a program that is not a library.\n\n
533
534 4. You may copy and distribute the Library (or a portion or
535derivative of it, under Section 2) in object code or executable form
536under the terms of Sections 1 and 2 above provided that you accompany
537it with the complete corresponding machine-readable source code, which
538must be distributed under the terms of Sections 1 and 2 above on a
539medium customarily used for software interchange.\n\n
540
541 If distribution of object code is made by offering access to copy
542from a designated place, then offering equivalent access to copy the
543source code from the same place satisfies the requirement to
544distribute the source code, even though third parties are not
545compelled to copy the source along with the object code.\n\n
546
547 5. A program that contains no derivative of any portion of the
548Library, but is designed to work with the Library by being compiled or
549linked with it, is called a \"work that uses the Library\". Such a
550work, in isolation, is not a derivative work of the Library, and
551therefore falls outside the scope of this License.\n\n
552
553 However, linking a \"work that uses the Library\" with the Library
554creates an executable that is a derivative of the Library (because it
555contains portions of the Library), rather than a \"work that uses the
556library\". The executable is therefore covered by this License.
557Section 6 states terms for distribution of such executables.\n\n
558
559 When a \"work that uses the Library\" uses material from a header file
560that is part of the Library, the object code for the work may be a
561derivative work of the Library even though the source code is not.
562Whether this is true is especially significant if the work can be
563linked without the Library, or if the work is itself a library. The
564threshold for this to be true is not precisely defined by law.\n\n
565
566 If such an object file uses only numerical parameters, data
567structure layouts and accessors, and small macros and small inline
568functions (ten lines or less in length), then the use of the object
569file is unrestricted, regardless of whether it is legally a derivative
570work. (Executables containing this object code plus portions of the
571Library will still fall under Section 6.)\n\n
572
573 Otherwise, if the work is a derivative of the Library, you may
574distribute the object code for the work under the terms of Section 6.
575Any executables containing that work also fall under Section 6,
576whether or not they are linked directly with the Library itself.\n\n
577
578 6. As an exception to the Sections above, you may also combine or
579link a \"work that uses the Library\" with the Library to produce a
580work containing portions of the Library, and distribute that work
581under terms of your choice, provided that the terms permit
582modification of the work for the customer\'s own use and reverse
583engineering for debugging such modifications.\n\n
584
585 You must give prominent notice with each copy of the work that the
586Library is used in it and that the Library and its use are covered by
587this License. You must supply a copy of this License. If the work
588during execution displays copyright notices, you must include the
589copyright notice for the Library among them, as well as a reference
590directing the user to the copy of this License. Also, you must do one
591of these things:\n\n
592
593a) Accompany the work with the complete corresponding
594machine-readable source code for the Library including whatever
595changes were used in the work (which must be distributed under
596Sections 1 and 2 above); and, if the work is an executable linked
597with the Library, with the complete machine-readable \"work that
598uses the Library\", as object code and/or source code, so that the
599user can modify the Library and then relink to produce a modified
600executable containing the modified Library. (It is understood
601that the user who changes the contents of definitions files in the
602Library will not necessarily be able to recompile the application
603to use the modified definitions.)\n\n
604
605b) Use a suitable shared library mechanism for linking with the
606Library. A suitable mechanism is one that (1) uses at run time a
607copy of the library already present on the user\'s computer system,
608rather than copying library functions into the executable, and (2)
609will operate properly with a modified version of the library, if
610the user installs one, as long as the modified version is
611interface-compatible with the version that the work was made with.\n\n
612
613c) Accompany the work with a written offer, valid for at
614least three years, to give the same user the materials
615specified in Subsection 6a, above, for a charge no more
616than the cost of performing this distribution.\n\n
617
618d) If distribution of the work is made by offering access to copy
619from a designated place, offer equivalent access to copy the above
620specified materials from the same place.\n\n
621
622e) Verify that the user has already received a copy of these
623materials or that you have already sent this user a copy.\n\n
624
625 For an executable, the required form of the \"work that uses the
626Library\" must include any data and utility programs needed for
627reproducing the executable from it. However, as a special exception,
628the materials to be distributed need not include anything that is
629normally distributed (in either source or binary form) with the major
630components (compiler, kernel, and so on) of the operating system on
631which the executable runs, unless that component itself accompanies
632the executable.\n\n
633
634 It may happen that this requirement contradicts the license
635restrictions of other proprietary libraries that do not normally
636accompany the operating system. Such a contradiction means you cannot
637use both them and the Library together in an executable that you
638distribute.\n\n
639
640 7. You may place library facilities that are a work based on the
641Library side-by-side in a single library together with other library
642facilities not covered by this License, and distribute such a combined
643library, provided that the separate distribution of the work based on
644the Library and of the other library facilities is otherwise
645permitted, and provided that you do these two things:\n\n
646
647a) Accompany the combined library with a copy of the same work
648based on the Library, uncombined with any other library
649facilities. This must be distributed under the terms of the
650Sections above.\n\n
651
652b) Give prominent notice with the combined library of the fact
653that part of it is a work based on the Library, and explaining
654where to find the accompanying uncombined form of the same work.\n\n
655
656 8. You may not copy, modify, sublicense, link with, or distribute
657the Library except as expressly provided under this License. Any
658attempt otherwise to copy, modify, sublicense, link with, or
659distribute the Library is void, and will automatically terminate your
660rights under this License. However, parties who have received copies,
661or rights, from you under this License will not have their licenses
662terminated so long as such parties remain in full compliance.\n\n
663
664 9. You are not required to accept this License, since you have not
665signed it. However, nothing else grants you permission to modify or
666distribute the Library or its derivative works. These actions are
667prohibited by law if you do not accept this License. Therefore, by
668modifying or distributing the Library (or any work based on the
669Library), you indicate your acceptance of this License to do so, and
670all its terms and conditions for copying, distributing or modifying
671the Library or works based on it.\n\n
672
673 10. Each time you redistribute the Library (or any work based on the
674Library), the recipient automatically receives a license from the
675original licensor to copy, distribute, link with or modify the Library
676subject to these terms and conditions. You may not impose any further
677restrictions on the recipients\' exercise of the rights granted herein.
678You are not responsible for enforcing compliance by third parties with
679this License.\n\n
680
681 11. If, as a consequence of a court judgment or allegation of patent
682infringement or for any other reason (not limited to patent issues),
683conditions are imposed on you (whether by court order, agreement or
684otherwise) that contradict the conditions of this License, they do not
685excuse you from the conditions of this License. If you cannot
686distribute so as to satisfy simultaneously your obligations under this
687License and any other pertinent obligations, then as a consequence you
688may not distribute the Library at all. For example, if a patent
689license would not permit royalty-free redistribution of the Library by
690all those who receive copies directly or indirectly through you, then
691the only way you could satisfy both it and this License would be to
692refrain entirely from distribution of the Library.\n\n
693
694If any portion of this section is held invalid or unenforceable under any
695particular circumstance, the balance of the section is intended to apply,
696and the section as a whole is intended to apply in other circumstances.\n\n
697
698It is not the purpose of this section to induce you to infringe any
699patents or other property right claims or to contest validity of any
700such claims; this section has the sole purpose of protecting the
701integrity of the free software distribution system which is
702implemented by public license practices. Many people have made
703generous contributions to the wide range of software distributed
704through that system in reliance on consistent application of that
705system; it is up to the author/donor to decide if he or she is willing
706to distribute software through any other system and a licensee cannot
707impose that choice.\n\n
708
709This section is intended to make thoroughly clear what is believed to
710be a consequence of the rest of this License.\n\n
711
712 12. If the distribution and/or use of the Library is restricted in
713certain countries either by patents or by copyrighted interfaces, the
714original copyright holder who places the Library under this License may add
715an explicit geographical distribution limitation excluding those countries,
716so that distribution is permitted only in or among countries not thus
717excluded. In such case, this License incorporates the limitation as if
718written in the body of this License.\n\n
719
720 13. The Free Software Foundation may publish revised and/or new
721versions of the Lesser General Public License from time to time.
722Such new versions will be similar in spirit to the present version,
723but may differ in detail to address new problems or concerns.\n\n
724
725Each version is given a distinguishing version number. If the Library
726specifies a version number of this License which applies to it and
727"any later version\", you have the option of following the terms and
728conditions either of that version or of any later version published by
729the Free Software Foundation. If the Library does not specify a
730license version number, you may choose any version ever published by
731the Free Software Foundation.\n\n
732
733 14. If you wish to incorporate parts of the Library into other free
734programs whose distribution conditions are incompatible with these,
735write to the author to ask for permission. For software which is
736copyrighted by the Free Software Foundation, write to the Free
737Software Foundation; we sometimes make exceptions for this. Our
738decision will be guided by the two goals of preserving the free status
739of all derivatives of our free software and of promoting the sharing
740and reuse of software generally.\n\n
741
742NO WARRANTY\n\n
743
744 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
745WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
746EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
747OTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY
748KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
749IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
750PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
751LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
752THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n
753
754 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
755WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
756AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
757FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
758CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
759LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
760RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
761FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
762SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
763DAMAGES.
764 </string>
765 <string name="license_opus" translatable="false">Opus</string>
766 <string name="license_opus_description" translatable="false">Modern audio compression for the internet</string>
767 <string name="license_opus_link" translatable="false">https://github.com/xiph/opus</string>
768 <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>
769 <string name="license_opus_text" translatable="false">
770Redistribution and use in source and binary forms, with or without
771modification, are permitted provided that the following conditions
772are met:\n\n
773
774- Redistributions of source code must retain the above copyright
775notice, this list of conditions and the following disclaimer.\n\n
776
777- Redistributions in binary form must reproduce the above copyright
778notice, this list of conditions and the following disclaimer in the
779documentation and/or other materials provided with the distribution.\n\n
780
781- Neither the name of Internet Society, IETF or IETF Trust, nor the
782names of specific contributors, may be used to endorse or promote
783products derived from this software without specific prior written
784permission.\n\n
785
786THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
787``AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
788LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
789A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
790OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
791EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
792PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
793PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
794LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
795NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
796SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n
797
798Opus is subject to the royalty-free patent licenses which are
799specified at:\n\n
800
801Xiph.Org Foundation:
802https://datatracker.ietf.org/ipr/1524/ \n\n
803
804Microsoft Corporation:
805https://datatracker.ietf.org/ipr/1914/ \n\n
806
807Broadcom Corporation:
808https://datatracker.ietf.org/ipr/1526/
809 </string>
810 <string name="license_sirit" translatable="false">Sirit</string>
811 <string name="license_sirit_description" translatable="false">A runtime SPIR-V assembler</string>
812 <string name="license_sirit_link" translatable="false">https://github.com/ReinUsesLisp/sirit</string>
813 <string name="license_sirit_copyright" translatable="false">Copyright © 2019, sirit All rights reserved.</string>
814 <string name="license_sirit_text" translatable="false">
815Redistribution and use in source and binary forms, with or without
816modification, are permitted provided that the following conditions are met:\n
817* Redistributions of source code must retain the above copyright
818 notice, this list of conditions and the following disclaimer.\n
819* Redistributions in binary form must reproduce the above copyright
820 notice, this list of conditions and the following disclaimer in the
821 documentation and/or other materials provided with the distribution.\n
822* Neither the name of the organization nor the
823 names of its contributors may be used to endorse or promote products
824 derived from this software without specific prior written permission.\n\n
825
826THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND
827ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
828WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
829DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
830DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
831(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
832LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
833ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
834(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
835SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
836 </string>
837 <string name="license_adreno_tools" translatable="false">Adreno Tools</string>
838 <string name="license_adreno_tools_description" translatable="false">A library for applying rootless Adreno GPU driver modifications/replacements</string>
839 <string name="license_adreno_tools_link" translatable="false">https://github.com/bylaws/libadrenotools</string>
840 <string name="license_adreno_tools_copyright" translatable="false">Copyright © 2021, Billy Laws</string>
841 <string name="license_adreno_tools_text" translatable="false">
842BSD 2-Clause License\n\n
843
844Redistribution and use in source and binary forms, with or without
845modification, are permitted provided that the following conditions are met:\n\n
846
8471. Redistributions of source code must retain the above copyright notice, this
848 list of conditions and the following disclaimer.\n\n
849
8502. Redistributions in binary form must reproduce the above copyright notice,
851 this list of conditions and the following disclaimer in the documentation
852 and/or other materials provided with the distribution.\n\n
853
854THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
855AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
856IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
857DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
858FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
859DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
860SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
861CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
862OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
863OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
864 </string>
865
349</resources> 866</resources>