Associate with NRO files

This commit adds the ability to open NRO files directly from a file browser rather than the emulator itself.
This commit is contained in:
◱ PixelyIon 2019-12-11 05:44:16 +05:30 committed by ◱ PixelyIon
parent 8d1545aabf
commit 4a72704c4d
5 changed files with 55 additions and 21 deletions

View File

@ -50,12 +50,41 @@
android:name="emu.skyline.GameActivity" android:name="emu.skyline.GameActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:screenOrientation="landscape"> android:screenOrientation="landscape">
<meta-data
android:name="android.app.lib_name"
android:value="skyline" />
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="emu.skyline.MainActivity" /> android:value="emu.skyline.MainActivity" />
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="application/nro"
android:pathPattern=".*\\.nro"
android:scheme="content"
tools:ignore="AppLinkUrlError" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="text/plain"
android:pathPattern=".*\\.nro"
android:scheme="content"
tools:ignore="AppLinkUrlError" />
<data
android:mimeType="application/octet-stream"
android:pathPattern=".*\\.nro"
android:scheme="content"
tools:ignore="AppLinkUrlError" />
<data
android:mimeType="application/nro"
android:scheme="content"
tools:ignore="AppLinkUrlError" />
</intent-filter>
</activity> </activity>
</application> </application>

View File

@ -9,6 +9,7 @@ import android.view.Surface
import android.view.SurfaceHolder import android.view.SurfaceHolder
import android.view.WindowManager import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import emu.skyline.loader.getTitleFormat
import kotlinx.android.synthetic.main.game_activity.* import kotlinx.android.synthetic.main.game_activity.*
import java.io.File import java.io.File
import java.lang.reflect.Method import java.lang.reflect.Method
@ -34,8 +35,8 @@ class GameActivity : AppCompatActivity(), SurfaceHolder.Callback, InputQueue.Cal
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.game_activity) setContentView(R.layout.game_activity)
rom = intent.getParcelableExtra("romUri")!! rom = intent.data!!
val romType = intent.getIntExtra("romType", 0) val romType = getTitleFormat(rom, contentResolver).ordinal
romFd = contentResolver.openFileDescriptor(rom, "r")!! romFd = contentResolver.openFileDescriptor(rom, "r")!!
val preference = File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml") val preference = File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml")
preferenceFd = ParcelFileDescriptor.open(preference, ParcelFileDescriptor.MODE_READ_WRITE) preferenceFd = ParcelFileDescriptor.open(preference, ParcelFileDescriptor.MODE_READ_WRITE)

View File

@ -4,7 +4,6 @@ import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.OpenableColumns
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -22,7 +21,6 @@ import emu.skyline.adapter.GameItem
import emu.skyline.loader.BaseLoader import emu.skyline.loader.BaseLoader
import emu.skyline.loader.NroLoader import emu.skyline.loader.NroLoader
import emu.skyline.loader.TitleEntry import emu.skyline.loader.TitleEntry
import emu.skyline.loader.TitleFormat
import emu.skyline.utility.RandomAccessDocument import emu.skyline.utility.RandomAccessDocument
import kotlinx.android.synthetic.main.main_activity.* import kotlinx.android.synthetic.main.main_activity.*
import java.io.File import java.io.File
@ -114,8 +112,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
val item = parent.getItemAtPosition(position) val item = parent.getItemAtPosition(position)
if (item is GameItem) { if (item is GameItem) {
val intent = Intent(this, GameActivity::class.java) val intent = Intent(this, GameActivity::class.java)
intent.putExtra("romUri", item.uri) intent.data = item.uri
intent.putExtra("romType", item.meta.romType.ordinal)
startActivity(intent) startActivity(intent)
} }
} }
@ -191,18 +188,13 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
} }
2 -> { 2 -> {
try { try {
val uri = (data!!.data!!)
val intent = Intent(this, GameActivity::class.java) val intent = Intent(this, GameActivity::class.java)
val uri = data!!.data!! intent.data = uri
intent.putExtra("romUri", uri) if (resultCode != 0)
var uriStr = "" startActivityForResult(intent, resultCode)
contentResolver.query(uri, null, null, null, null)?.use { cursor -> else
val nameIndex: Int = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) startActivity(intent)
cursor.moveToFirst()
uriStr = cursor.getString(nameIndex)
}
val type = TitleFormat.valueOf(uriStr.substring(uriStr.lastIndexOf(".") + 1).toUpperCase(Locale.ROOT))
intent.putExtra("romType", type)
startActivity(intent)
} catch (e: Exception) { } catch (e: Exception) {
notifyUser(e.message!!) notifyUser(e.message!!)
} }

View File

@ -1,5 +1,6 @@
package emu.skyline.loader package emu.skyline.loader
import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
@ -12,11 +13,22 @@ import java.io.IOException
import java.io.ObjectInputStream import java.io.ObjectInputStream
import java.io.ObjectOutputStream import java.io.ObjectOutputStream
import java.io.Serializable import java.io.Serializable
import java.util.*
enum class TitleFormat { enum class TitleFormat {
NRO, XCI, NSP NRO, XCI, NSP
} }
fun getTitleFormat(uri: Uri, contentResolver: ContentResolver): TitleFormat {
var uriStr = ""
contentResolver.query(uri, null, null, null, null)?.use { cursor ->
val nameIndex: Int = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
cursor.moveToFirst()
uriStr = cursor.getString(nameIndex)
}
return TitleFormat.valueOf(uriStr.substring(uriStr.lastIndexOf(".") + 1).toUpperCase(Locale.ROOT))
}
internal class TitleEntry(var name: String, var author: String, var romType: TitleFormat, var valid: Boolean, @Transient var uri: Uri, @Transient var icon: Bitmap) : Serializable { internal class TitleEntry(var name: String, var author: String, var romType: TitleFormat, var valid: Boolean, @Transient var uri: Uri, @Transient var icon: Bitmap) : Serializable {
constructor(context: Context, author: String, romType: TitleFormat, valid: Boolean, uri: Uri) : this("", author, romType, valid, uri, context.resources.getDrawable(R.drawable.ic_missing, context.theme).toBitmap(256, 256)) { constructor(context: Context, author: String, romType: TitleFormat, valid: Boolean, uri: Uri) : this("", author, romType, valid, uri, context.resources.getDrawable(R.drawable.ic_missing, context.theme).toBitmap(256, 256)) {
context.contentResolver.query(uri, null, null, null, null)?.use { cursor -> context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->

View File

@ -13,7 +13,7 @@ class ThemePreference : ListPreference {
constructor(context: Context?) : super(context) constructor(context: Context?) : super(context)
override fun callChangeListener(newValue: Any?): Boolean { override fun callChangeListener(newValue: Any?): Boolean {
AppCompatDelegate.setDefaultNightMode(when((newValue as String).toInt()) { AppCompatDelegate.setDefaultNightMode(when ((newValue as String).toInt()) {
0 -> AppCompatDelegate.MODE_NIGHT_NO 0 -> AppCompatDelegate.MODE_NIGHT_NO
1 -> AppCompatDelegate.MODE_NIGHT_YES 1 -> AppCompatDelegate.MODE_NIGHT_YES
2 -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM 2 -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM