committed by
bunnei
15 changed files with 327 additions and 8 deletions
-
15src/android/app/src/main/AndroidManifest.xml
-
12src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.java
-
20src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
-
32src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
-
7src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.kt
-
165src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt
-
11src/android/app/src/main/jni/emu_window/emu_window.cpp
-
3src/android/app/src/main/jni/emu_window/emu_window.h
-
20src/android/app/src/main/jni/native.cpp
-
8src/android/app/src/main/jni/native.h
-
6src/android/app/src/main/res/menu/menu_game_grid.xml
-
2src/android/app/src/main/res/values/strings.xml
-
6src/android/app/src/main/res/xml/nfc_tech_filter.xml
-
26src/input_common/drivers/virtual_amiibo.cpp
-
2src/input_common/drivers/virtual_amiibo.h
@ -0,0 +1,165 @@ |
|||
package org.yuzu.yuzu_emu.utils |
|||
|
|||
import android.app.Activity |
|||
import android.app.PendingIntent |
|||
import android.content.Intent |
|||
import android.content.IntentFilter |
|||
import android.nfc.NfcAdapter |
|||
import android.nfc.Tag |
|||
import android.nfc.tech.NfcA |
|||
import android.os.Build |
|||
import android.os.Handler |
|||
import android.os.Looper |
|||
import org.yuzu.yuzu_emu.NativeLibrary |
|||
import java.io.IOException |
|||
|
|||
class NfcReader(private val activity: Activity) { |
|||
private var nfcAdapter: NfcAdapter? = null |
|||
private var pendingIntent: PendingIntent? = null |
|||
|
|||
fun initialize() { |
|||
nfcAdapter = NfcAdapter.getDefaultAdapter(activity) ?: return |
|||
|
|||
pendingIntent = PendingIntent.getActivity( |
|||
activity, |
|||
0, Intent(activity, activity.javaClass), |
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) |
|||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE |
|||
else PendingIntent.FLAG_UPDATE_CURRENT |
|||
) |
|||
|
|||
val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) |
|||
tagDetected.addCategory(Intent.CATEGORY_DEFAULT) |
|||
} |
|||
|
|||
fun startScanning() { |
|||
nfcAdapter?.enableForegroundDispatch(activity, pendingIntent, null, null) |
|||
} |
|||
|
|||
fun stopScanning() { |
|||
nfcAdapter?.disableForegroundDispatch(activity) |
|||
} |
|||
|
|||
fun onNewIntent(intent: Intent) { |
|||
val action = intent.action |
|||
if (NfcAdapter.ACTION_TAG_DISCOVERED != action |
|||
&& NfcAdapter.ACTION_TECH_DISCOVERED != action |
|||
&& NfcAdapter.ACTION_NDEF_DISCOVERED != action |
|||
) { |
|||
return |
|||
} |
|||
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { |
|||
val tag = |
|||
intent.getParcelableExtra(NfcAdapter.EXTRA_TAG, Tag::class.java) ?: return |
|||
readTagData(tag) |
|||
return |
|||
} |
|||
|
|||
val tag = |
|||
intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG) ?: return |
|||
readTagData(tag) |
|||
} |
|||
|
|||
private fun readTagData(tag: Tag) { |
|||
if (!tag.techList.contains("android.nfc.tech.NfcA")) { |
|||
return |
|||
} |
|||
|
|||
val amiibo = NfcA.get(tag) ?: return |
|||
amiibo.connect() |
|||
|
|||
val tagData = ntag215ReadAll(amiibo) ?: return |
|||
NativeLibrary.onReadNfcTag(tagData) |
|||
|
|||
nfcAdapter?.ignore( |
|||
tag, |
|||
1000, |
|||
{ NativeLibrary.onRemoveNfcTag() }, |
|||
Handler(Looper.getMainLooper()) |
|||
) |
|||
} |
|||
|
|||
private fun ntag215ReadAll(amiibo: NfcA): ByteArray? { |
|||
val bufferSize = amiibo.maxTransceiveLength; |
|||
val tagSize = 0x21C |
|||
val pageSize = 4 |
|||
val lastPage = tagSize / pageSize - 1 |
|||
val tagData = ByteArray(tagSize) |
|||
|
|||
// We need to read the ntag in steps otherwise we overflow the buffer |
|||
for (i in 0..tagSize step bufferSize - 1) { |
|||
val dataStart = i / pageSize |
|||
var dataEnd = (i + bufferSize) / pageSize |
|||
|
|||
if (dataEnd > lastPage) { |
|||
dataEnd = lastPage |
|||
} |
|||
|
|||
try { |
|||
val data = ntag215FastRead(amiibo, dataStart, dataEnd - 1) |
|||
System.arraycopy(data, 0, tagData, i, (dataEnd - dataStart) * pageSize) |
|||
} catch (e: IOException) { |
|||
return null; |
|||
} |
|||
} |
|||
return tagData |
|||
} |
|||
|
|||
private fun ntag215Read(amiibo: NfcA, page: Int): ByteArray? { |
|||
return amiibo.transceive( |
|||
byteArrayOf( |
|||
0x30.toByte(), |
|||
(page and 0xFF).toByte() |
|||
) |
|||
) |
|||
} |
|||
|
|||
private fun ntag215FastRead(amiibo: NfcA, start: Int, end: Int): ByteArray? { |
|||
return amiibo.transceive( |
|||
byteArrayOf( |
|||
0x3A.toByte(), |
|||
(start and 0xFF).toByte(), |
|||
(end and 0xFF).toByte() |
|||
) |
|||
) |
|||
} |
|||
|
|||
private fun ntag215PWrite( |
|||
amiibo: NfcA, |
|||
page: Int, |
|||
data1: Int, |
|||
data2: Int, |
|||
data3: Int, |
|||
data4: Int |
|||
): ByteArray? { |
|||
return amiibo.transceive( |
|||
byteArrayOf( |
|||
0xA2.toByte(), |
|||
(page and 0xFF).toByte(), |
|||
(data1 and 0xFF).toByte(), |
|||
(data2 and 0xFF).toByte(), |
|||
(data3 and 0xFF).toByte(), |
|||
(data4 and 0xFF).toByte() |
|||
) |
|||
) |
|||
} |
|||
|
|||
private fun ntag215PwdAuth( |
|||
amiibo: NfcA, |
|||
data1: Int, |
|||
data2: Int, |
|||
data3: Int, |
|||
data4: Int |
|||
): ByteArray? { |
|||
return amiibo.transceive( |
|||
byteArrayOf( |
|||
0x1B.toByte(), |
|||
(data1 and 0xFF).toByte(), |
|||
(data2 and 0xFF).toByte(), |
|||
(data3 and 0xFF).toByte(), |
|||
(data4 and 0xFF).toByte() |
|||
) |
|||
) |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
|||
<tech-list> |
|||
<tech>android.nfc.tech.NfcA</tech> |
|||
</tech-list> |
|||
</resources> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue