Compare commits

..

No commits in common. "master" and "1.2.0" have entirely different histories.

15 changed files with 327 additions and 702 deletions

View File

@ -11,8 +11,8 @@ android {
applicationId "com.github.brokenithm" applicationId "com.github.brokenithm"
minSdkVersion 17 minSdkVersion 17
targetSdkVersion 30 targetSdkVersion 30
versionCode 10300 versionCode 10200
versionName "1.3.0" versionName "1.2.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -35,15 +35,14 @@ android {
dependencies { dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.3.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.4.0' implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'net.cachapa.expandablelayout:expandablelayout:2.9.2' implementation 'net.cachapa.expandablelayout:expandablelayout:2.9.2'
implementation 'androidx.preference:preference-ktx:1.1.1'
} }

View File

@ -4,7 +4,6 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.NFC"/>
<application <application
android:name=".BrokenithmApplication" android:name=".BrokenithmApplication"
@ -17,17 +16,12 @@
<activity android:name=".activity.MainActivity" <activity android:name=".activity.MainActivity"
android:screenOrientation="landscape" android:screenOrientation="landscape"
android:configChanges="uiMode|orientation"> android:configChanges="uiMode|orientation">
<meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filters" />
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
</activity> </activity>
<activity android:name=".activity.SettingsActivity" android:configChanges="uiMode|orientation" />
</application> </application>
</manifest> </manifest>

View File

@ -1,89 +1,77 @@
package com.github.brokenithm package com.github.brokenithm
import android.app.Application import android.app.Application
import android.content.Context
import android.content.SharedPreferences
class BrokenithmApplication : Application() { class BrokenithmApplication : Application() {
var lastServer: String
get() {
val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
return config.getString("server", "") ?: ""
}
set(value) {
val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
config.edit().putString("server", value).apply()
}
abstract class BasePreference<T>(context: Context, fileName: String) { var enableAir: Boolean
protected val config: SharedPreferences = context.getSharedPreferences(fileName, MODE_PRIVATE) get() {
abstract fun value(): T val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
abstract fun update(value: T) return config.getBoolean("enable_air", true)
} }
set(value) {
val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
config.edit().putBoolean("enable_air", value).apply()
}
abstract class Settings<T>(context: Context) : BasePreference<T>(context, settings_preference) var airSource: Int
get() {
val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
return config.getInt("air_source", 3)
}
set(value) {
val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
config.edit().putInt("air_source", value).apply()
}
open class StringPreference( var simpleAir: Boolean
context: Context, get() {
private val key: String, val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
private val defValue: String return config.getBoolean("simple_air", false)
) : Settings<String>(context) { }
override fun value() = config.getString(key, defValue) ?: defValue set(value) {
override fun update(value: String) = config.edit().putString(key, value).apply() val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
} config.edit().putBoolean("simple_air", value).apply()
}
open class BooleanPreference( var showDelay: Boolean
context: Context, get() {
private val key: String, val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
private val defValue: Boolean return config.getBoolean("show_delay", false)
) : Settings<Boolean>(context) { }
override fun value() = config.getBoolean(key, defValue) set(value) {
override fun update(value: Boolean) = config.edit().putBoolean(key, value).apply() val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
} config.edit().putBoolean("show_delay", value).apply()
}
open class IntegerPreference( var enableVibrate: Boolean
context: Context, get() {
private val key: String, val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
private val defValue: Int return config.getBoolean("enable_vibrate", true)
) : Settings<Int>(context) { }
override fun value() = config.getInt(key, defValue) set(value) {
override fun update(value: Int) = config.edit().putInt(key, value).apply() val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
} config.edit().putBoolean("enable_vibrate", value).apply()
}
open class FloatPreference( var tcpMode: Boolean
context: Context, get() {
private val key: String, val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
private val defValue: Float return config.getBoolean("tcp_mode", false)
) : Settings<Float>(context) { }
override fun value() = config.getString(key, defValue.toString())?.toFloat() ?: defValue set(value) {
override fun update(value: Float) = config.edit().putString(key, value.toString()).apply() val config = getSharedPreferences(settings_preference, MODE_PRIVATE)
} config.edit().putBoolean("tcp_mode", value).apply()
}
lateinit var lastServer : StringPreference
lateinit var enableAir : BooleanPreference
lateinit var airSource : IntegerPreference
lateinit var simpleAir : BooleanPreference
lateinit var showDelay : BooleanPreference
lateinit var enableVibrate : BooleanPreference
lateinit var tcpMode : BooleanPreference
lateinit var enableNFC : BooleanPreference
lateinit var wideTouchRange : BooleanPreference
lateinit var enableTouchSize : BooleanPreference
lateinit var fatTouchThreshold : FloatPreference
lateinit var extraFatTouchThreshold : FloatPreference
lateinit var gyroAirLowestBound : FloatPreference
lateinit var gyroAirHighestBound : FloatPreference
lateinit var accelAirThreshold : FloatPreference
override fun onCreate() {
super.onCreate()
lastServer = StringPreference(this, "server", "")
enableAir = BooleanPreference(this, "enable_air", true)
airSource = IntegerPreference(this, "air_source", 3)
simpleAir = BooleanPreference(this, "simple_air", false)
showDelay = BooleanPreference(this, "show_delay", false)
enableVibrate = BooleanPreference(this, "enable_vibrate", true)
tcpMode = BooleanPreference(this, "tcp_mode", false)
enableNFC = BooleanPreference(this, "enable_nfc", true)
wideTouchRange = BooleanPreference(this, "wide_touch_range", false)
enableTouchSize = BooleanPreference(this, "enable_touch_size", false)
fatTouchThreshold = FloatPreference(this, "fat_touch_threshold", 0.027f)
extraFatTouchThreshold = FloatPreference(this, "extra_fat_touch_threshold", 0.035f)
gyroAirLowestBound = FloatPreference(this, "gyro_air_lowest", 0.8f)
gyroAirHighestBound = FloatPreference(this, "gyro_air_highest", 1.35f)
accelAirThreshold = FloatPreference(this, "accel_air_threshold", 2f)
}
companion object { companion object {
private const val settings_preference = "settings" private const val settings_preference = "settings"

View File

@ -1,20 +1,14 @@
package com.github.brokenithm.activity package com.github.brokenithm.activity
import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.* import android.graphics.*
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.hardware.Sensor import android.hardware.Sensor
import android.hardware.SensorEvent import android.hardware.SensorEvent
import android.hardware.SensorEventListener import android.hardware.SensorEventListener
import android.hardware.SensorManager import android.hardware.SensorManager
import android.nfc.NfcAdapter
import android.nfc.NfcManager
import android.nfc.Tag
import android.nfc.tech.MifareClassic
import android.os.* import android.os.*
import android.util.Log import android.util.DisplayMetrics
import android.view.* import android.view.*
import android.widget.* import android.widget.*
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -22,7 +16,6 @@ import androidx.lifecycle.lifecycleScope
import com.github.brokenithm.BrokenithmApplication import com.github.brokenithm.BrokenithmApplication
import com.github.brokenithm.R import com.github.brokenithm.R
import com.github.brokenithm.util.AsyncTaskUtil import com.github.brokenithm.util.AsyncTaskUtil
import com.github.brokenithm.util.FeliCa
import net.cachapa.expandablelayout.ExpandableLayout import net.cachapa.expandablelayout.ExpandableLayout
import java.net.* import java.net.*
import java.nio.ByteBuffer import java.nio.ByteBuffer
@ -48,9 +41,8 @@ class MainActivity : AppCompatActivity() {
private val numOfGaps = 16 private val numOfGaps = 16
private val buttonWidthToGap = 7.428571f private val buttonWidthToGap = 7.428571f
private val numOfAirBlock = 6 private val numOfAirBlock = 6
private var mEnableTouchSize = false private val fatTouchSizeThreshold = 0.027f
private var mFatTouchSizeThreshold = 0.027f private val extraFatTouchSizeThreshold = 0.035f
private var mExtraFatTouchSizeThreshold = 0.035f
private var mCurrentDelay = 0f private var mCurrentDelay = 0f
// Buttons // Buttons
@ -69,7 +61,6 @@ class MainActivity : AppCompatActivity() {
private lateinit var mButtonRenderer: View private lateinit var mButtonRenderer: View
// vibrator // vibrator
private var mEnableVibrate = true
private lateinit var vibrator: Vibrator private lateinit var vibrator: Vibrator
private lateinit var vibratorTask: AsyncTaskUtil.AsyncTask<Unit, Unit, Unit> private lateinit var vibratorTask: AsyncTaskUtil.AsyncTask<Unit, Unit, Unit>
private lateinit var vibrateMethod: (Long) -> Unit private lateinit var vibrateMethod: (Long) -> Unit
@ -82,6 +73,7 @@ class MainActivity : AppCompatActivity() {
private var mSimpleAir = false private var mSimpleAir = false
private var mDebugInfo = false private var mDebugInfo = false
private var mShowDelay = false private var mShowDelay = false
private var mEnableVibrate = true
private lateinit var mDelayText: TextView private lateinit var mDelayText: TextView
private var windowWidth = 0f private var windowWidth = 0f
private var windowHeight = 0f private var windowHeight = 0f
@ -90,10 +82,9 @@ class MainActivity : AppCompatActivity() {
// sensor // sensor
private var mSensorManager: SensorManager? = null private var mSensorManager: SensorManager? = null
private var mSensorCallback: ((Float) -> Unit)? = null private var mSensorCallback: ((Float) -> Unit)? = null
private var mGyroLowestBound = 0.8f
private var mGyroHighestBound = 1.35f
private var mAccelThreshold = 2f
private val listener = object : SensorEventListener { private val listener = object : SensorEventListener {
val threshold = 2f
var current = 0 var current = 0
var lastAcceleration = 0f var lastAcceleration = 0f
@ -103,7 +94,6 @@ class MainActivity : AppCompatActivity() {
override fun onSensorChanged(event: SensorEvent?) { override fun onSensorChanged(event: SensorEvent?) {
event ?: return event ?: return
val threshold = mAccelThreshold
when (event.sensor.type) { when (event.sensor.type) {
Sensor.TYPE_LINEAR_ACCELERATION -> { Sensor.TYPE_LINEAR_ACCELERATION -> {
if (mAirSource != 2) if (mAirSource != 2)
@ -135,92 +125,6 @@ class MainActivity : AppCompatActivity() {
} }
} }
// nfc
private fun Byte.getBit(bit: Int) = (toInt() ushr bit) and 0x1
private fun MifareClassic.authenticateBlock(blockIndex: Int, keyA: ByteArray, keyB: ByteArray, write: Boolean = false): Boolean {
// check access bits
val sectorIndex = blockToSector(blockIndex)
val accessBitsBlock = sectorToBlock(sectorIndex) + 3
if (!authenticateSectorWithKeyA(sectorIndex, keyA)) return false
val accessBits = readBlock(accessBitsBlock)
val targetBit = blockIndex % 4
val bitC1 = accessBits[7].getBit(targetBit + 4)
val bitC2 = accessBits[8].getBit(targetBit)
val bitC3 = accessBits[8].getBit(targetBit + 4)
val allBits = (bitC1 shl 2) or (bitC2 shl 1) or bitC3
return if (write) {
when (allBits) {
0 -> true
3, 4, 6 -> authenticateSectorWithKeyB(sectorIndex, keyB)
else -> false
}
} else {
when (allBits) {
7 -> false
3, 5 -> authenticateSectorWithKeyB(sectorIndex, keyB)
else -> true
}
}
}
private fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
enum class CardType {
CARD_AIME, CARD_FELICA
}
private var adapter: NfcAdapter? = null
private val mAimeKey = byteArrayOf(0x57, 0x43, 0x43, 0x46, 0x76, 0x32)
private val mBanaKey = byteArrayOf(0x60, -0x70, -0x30, 0x06, 0x32, -0x0b)
private var mEnableNFC = true
private var hasCard = false
private var cardType = CardType.CARD_AIME
private val cardId = ByteArray(10)
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) ?: return
val felica = FeliCa.get(tag)
if (felica != null) {
thread {
try {
felica.connect()
felica.poll()
felica.IDm?.copyInto(cardId) ?: throw IllegalStateException("Failed to fetch IDm from FeliCa")
cardId[8] = 0
cardId[9] = 0
cardType = CardType.CARD_FELICA
hasCard = true
Log.d(TAG, "Found FeliCa card: ${cardId.toHexString().removeRange(16..19)}")
while (felica.isConnected) Thread.sleep(50)
hasCard = false
felica.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
return
}
val mifare = MifareClassic.get(tag) ?: return
thread {
try {
mifare.connect()
if (mifare.authenticateBlock(2, keyA = mAimeKey, keyB = mAimeKey) ||
mifare.authenticateBlock(2, keyA = mBanaKey, keyB = mAimeKey)) {
Thread.sleep(100)
val block = mifare.readBlock(2)
block.copyInto(cardId, 0, 6, 16)
cardType = CardType.CARD_AIME
hasCard = true
Log.d(TAG, "Found Aime card: ${cardId.toHexString()}")
while (mifare.isConnected) Thread.sleep(50)
hasCard = false
} else {
Log.d(TAG, "NFC auth failed")
}
mifare.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
@ -228,8 +132,6 @@ class MainActivity : AppCompatActivity() {
setImmersive() setImmersive()
app = application as BrokenithmApplication app = application as BrokenithmApplication
vibrator = applicationContext.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator vibrator = applicationContext.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
val nfcManager = getSystemService(Context.NFC_SERVICE) as NfcManager
adapter = nfcManager.defaultAdapter
vibrateMethod = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { vibrateMethod = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
{ {
@ -241,13 +143,18 @@ class MainActivity : AppCompatActivity() {
} }
} }
val settings = findViewById<Button>(R.id.button_settings)
settings.setOnClickListener { startActivity(Intent(this, SettingsActivity::class.java)) }
mDelayText = findViewById(R.id.text_delay) mDelayText = findViewById(R.id.text_delay)
findViewById<CheckBox>(R.id.check_vibrate).apply {
setOnCheckedChangeListener { _, isChecked ->
mEnableVibrate = isChecked
app.enableVibrate = isChecked
}
isChecked = app.enableVibrate
}
val editServer = findViewById<EditText>(R.id.edit_server).apply { val editServer = findViewById<EditText>(R.id.edit_server).apply {
setText(app.lastServer.value()) setText(app.lastServer)
} }
findViewById<Button>(R.id.button_start).setOnClickListener { findViewById<Button>(R.id.button_start).setOnClickListener {
val server = editServer.text.toString() val server = editServer.text.toString()
@ -259,9 +166,8 @@ class MainActivity : AppCompatActivity() {
mExitFlag = false mExitFlag = false
(it as Button).setText(R.string.stop) (it as Button).setText(R.string.stop)
editServer.isEnabled = false editServer.isEnabled = false
settings.isEnabled = false
app.lastServer.update(server) app.lastServer = server
val address = parseAddress(server) val address = parseAddress(server)
if (!mTCPMode) if (!mTCPMode)
sendConnect(address) sendConnect(address)
@ -274,7 +180,6 @@ class MainActivity : AppCompatActivity() {
mExitFlag = true mExitFlag = true
(it as Button).setText(R.string.start) (it as Button).setText(R.string.start)
editServer.isEnabled = true editServer.isEnabled = true
settings.isEnabled = true
senderTask.cancel() senderTask.cancel()
receiverTask.cancel() receiverTask.cancel()
pingPongTask.cancel() pingPongTask.cancel()
@ -291,7 +196,16 @@ class MainActivity : AppCompatActivity() {
} }
val checkSimpleAir = findViewById<CheckBox>(R.id.check_simple_air) val checkSimpleAir = findViewById<CheckBox>(R.id.check_simple_air)
mAirSource = app.airSource.value() findViewById<CheckBox>(R.id.check_enable_air).apply {
setOnCheckedChangeListener { _, isChecked ->
mEnableAir = isChecked
checkSimpleAir.isEnabled = isChecked
app.enableAir = isChecked
}
isChecked = app.enableAir
checkSimpleAir.isEnabled = isChecked
}
mAirSource = app.airSource
findViewById<TextView>(R.id.text_switch_air).apply { findViewById<TextView>(R.id.text_switch_air).apply {
setOnClickListener { setOnClickListener {
mAirSource = when (mAirSource) { mAirSource = when (mAirSource) {
@ -318,7 +232,7 @@ class MainActivity : AppCompatActivity() {
0 0
} }
} }
app.airSource.update(mAirSource) app.airSource = mAirSource
} }
text = getString(when (mAirSource) { text = getString(when (mAirSource) {
0 -> { checkSimpleAir.isEnabled = false; R.string.disable_air } 0 -> { checkSimpleAir.isEnabled = false; R.string.disable_air }
@ -330,12 +244,12 @@ class MainActivity : AppCompatActivity() {
checkSimpleAir.apply { checkSimpleAir.apply {
setOnCheckedChangeListener { _, isChecked -> setOnCheckedChangeListener { _, isChecked ->
mSimpleAir = isChecked mSimpleAir = isChecked
app.simpleAir.update(isChecked) app.simpleAir = isChecked
} }
isChecked = app.simpleAir.value() isChecked = app.simpleAir
} }
mEnableAir = app.enableAir.value() mEnableAir = app.enableAir
mSimpleAir = app.simpleAir.value() mSimpleAir = app.simpleAir
findViewById<View>(R.id.button_test).setOnTouchListener { view, event -> findViewById<View>(R.id.button_test).setOnTouchListener { view, event ->
mTestButton = when(event.actionMasked) { mTestButton = when(event.actionMasked) {
@ -358,12 +272,12 @@ class MainActivity : AppCompatActivity() {
setOnCheckedChangeListener { _, isChecked -> setOnCheckedChangeListener { _, isChecked ->
mShowDelay = isChecked mShowDelay = isChecked
mDelayText.visibility = if (isChecked) View.VISIBLE else View.GONE mDelayText.visibility = if (isChecked) View.VISIBLE else View.GONE
app.showDelay.update(isChecked) app.showDelay = isChecked
} }
isChecked = app.showDelay.value() isChecked = app.showDelay
} }
mTCPMode = app.tcpMode.value() mTCPMode = app.tcpMode
findViewById<TextView>(R.id.text_mode).apply { findViewById<TextView>(R.id.text_mode).apply {
text = getString(if (mTCPMode) R.string.tcp else R.string.udp) text = getString(if (mTCPMode) R.string.tcp else R.string.udp)
setOnClickListener { setOnClickListener {
@ -376,7 +290,7 @@ class MainActivity : AppCompatActivity() {
mTCPMode = true mTCPMode = true
R.string.tcp R.string.tcp
}) })
app.tcpMode.update(mTCPMode) app.tcpMode = mTCPMode
} }
} }
initTasks() initTasks()
@ -386,8 +300,8 @@ class MainActivity : AppCompatActivity() {
vibratorTask.execute(lifecycleScope) vibratorTask.execute(lifecycleScope)
mSensorCallback = { mSensorCallback = {
val lowest = mGyroLowestBound val lowest = 0.8f
val highest = mGyroHighestBound val highest = 1.35f
val steps = (highest - lowest) / numOfAirBlock val steps = (highest - lowest) / numOfAirBlock
val current = abs(it) val current = abs(it)
mCurrentAirHeight = if (mSimpleAir) { mCurrentAirHeight = if (mSimpleAir) {
@ -445,7 +359,11 @@ class MainActivity : AppCompatActivity() {
val textInfo = findViewById<TextView>(R.id.text_info) val textInfo = findViewById<TextView>(R.id.text_info)
findViewById<CheckBox>(R.id.check_debug).setOnCheckedChangeListener { _, isChecked -> findViewById<CheckBox>(R.id.check_debug).setOnCheckedChangeListener { _, isChecked ->
mDebugInfo = isChecked mDebugInfo = isChecked
textInfo.visibility = if (isChecked) View.VISIBLE else View.GONE textInfo.visibility = if (isChecked) {
View.VISIBLE
} else {
View.GONE
}
} }
gapWidth = windowWidth / (numOfButtons * buttonWidthToGap + numOfGaps) gapWidth = windowWidth / (numOfButtons * buttonWidthToGap + numOfGaps)
@ -499,64 +417,44 @@ class MainActivity : AppCompatActivity() {
var index = pointPos.toInt() var index = pointPos.toInt()
if (index > numOfButtons) index = numOfButtons if (index > numOfButtons) index = numOfButtons
if (mEnableTouchSize) { var centerButton = index * 2
var centerButton = index * 2 if (touchedButtons.contains(centerButton)) centerButton++
if (touchedButtons.contains(centerButton)) centerButton++ var leftButton = ((index - 1) * 2).coerceAtLeast(0)
var leftButton = ((index - 1) * 2).coerceAtLeast(0) if (touchedButtons.contains(leftButton)) leftButton++
if (touchedButtons.contains(leftButton)) leftButton++ var rightButton = ((index + 1) * 2).coerceAtMost(numOfButtons * 2)
var rightButton = ((index + 1) * 2).coerceAtMost(numOfButtons * 2) if (touchedButtons.contains(rightButton)) rightButton++
if (touchedButtons.contains(rightButton)) rightButton++ var left2Button = ((index - 2) * 2).coerceAtLeast(0)
var left2Button = ((index - 2) * 2).coerceAtLeast(0) if (touchedButtons.contains(left2Button)) left2Button++
if (touchedButtons.contains(left2Button)) left2Button++ var right2Button = ((index + 2) * 2).coerceAtMost(numOfButtons * 2)
var right2Button = ((index + 2) * 2).coerceAtMost(numOfButtons * 2) if (touchedButtons.contains(right2Button)) right2Button++
if (touchedButtons.contains(right2Button)) right2Button++
val currentSize = event.getSize(i) val currentSize = event.getSize(i)
maxTouchedSize = maxTouchedSize.coerceAtLeast(currentSize) maxTouchedSize = maxTouchedSize.coerceAtLeast(currentSize)
touchedButtons.add(centerButton) touchedButtons.add(centerButton)
when ((pointPos - index) * 4) { when ((pointPos - index) * 4) {
in 0f..1f -> { in 0f..1f -> {
touchedButtons.add(leftButton) touchedButtons.add(leftButton)
if (currentSize >= mExtraFatTouchSizeThreshold) { if (currentSize >= extraFatTouchSizeThreshold) {
touchedButtons.add(left2Button) touchedButtons.add(left2Button)
touchedButtons.add(rightButton)
}
}
in 1f..3f -> {
if (currentSize >= mFatTouchSizeThreshold) {
touchedButtons.add(leftButton)
touchedButtons.add(rightButton)
}
if (currentSize >= mExtraFatTouchSizeThreshold) {
touchedButtons.add(left2Button)
touchedButtons.add(right2Button)
}
}
in 3f..4f -> {
touchedButtons.add(rightButton) touchedButtons.add(rightButton)
if (currentSize >= mExtraFatTouchSizeThreshold) {
touchedButtons.add(leftButton)
touchedButtons.add(right2Button)
}
} }
} }
} else { in 1f..3f -> {
if (index > 15) index = 15 if (currentSize >= fatTouchSizeThreshold) {
var targetIndex = index * 2 touchedButtons.add(leftButton)
if (touchedButtons.contains(targetIndex)) targetIndex++ touchedButtons.add(rightButton)
touchedButtons.add(targetIndex)
if (index > 0) {
if ((pointPos - index) * 4 < 1) {
targetIndex = (index - 1) * 2
if (touchedButtons.contains(targetIndex)) targetIndex++
touchedButtons.add(targetIndex)
} }
} else if (index < 31) { if (currentSize >= extraFatTouchSizeThreshold) {
if ((pointPos - index) * 4 > 3) { touchedButtons.add(left2Button)
targetIndex = (index + 1) * 2 touchedButtons.add(right2Button)
if (touchedButtons.contains(targetIndex)) targetIndex++ }
touchedButtons.add(targetIndex) }
in 3f..4f -> {
touchedButtons.add(rightButton)
if (currentSize >= extraFatTouchSizeThreshold) {
touchedButtons.add(leftButton)
touchedButtons.add(right2Button)
} }
} }
} }
@ -590,43 +488,11 @@ class MainActivity : AppCompatActivity() {
mSensorManager?.registerListener(listener, gyro, 10000) mSensorManager?.registerListener(listener, gyro, 10000)
val accel = mSensorManager?.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION) val accel = mSensorManager?.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION)
mSensorManager?.registerListener(listener, accel, 10000) mSensorManager?.registerListener(listener, accel, 10000)
enableNfcForegroundDispatch()
loadPreference()
}
private fun loadPreference() {
mEnableTouchSize = app.enableTouchSize.value()
mFatTouchSizeThreshold = app.fatTouchThreshold.value()
mExtraFatTouchSizeThreshold = app.extraFatTouchThreshold.value()
mEnableNFC = app.enableNFC.value()
mEnableVibrate = app.enableVibrate.value()
mGyroLowestBound = app.gyroAirLowestBound.value()
mGyroHighestBound = app.gyroAirHighestBound.value()
mAccelThreshold = app.accelAirThreshold.value()
}
private fun enableNfcForegroundDispatch() {
try {
val intent = Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
val nfcPendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
adapter?.enableForegroundDispatch(this, nfcPendingIntent, null, null)
} catch (ex: IllegalStateException) {
Log.e(TAG, "Error enabling NFC foreground dispatch", ex)
}
}
private fun disableNfcForegroundDispatch() {
try {
adapter?.disableForegroundDispatch(this)
} catch (ex: IllegalStateException) {
Log.e(TAG, "Error disabling NFC foreground dispatch", ex)
}
} }
override fun onPause() { override fun onPause() {
disableNfcForegroundDispatch()
mSensorManager?.unregisterListener(listener)
super.onPause() super.onPause()
mSensorManager?.unregisterListener(listener)
} }
override fun onWindowFocusChanged(hasFocus: Boolean) { override fun onWindowFocusChanged(hasFocus: Boolean) {
@ -678,7 +544,6 @@ class MainActivity : AppCompatActivity() {
} }
} }
private fun Char.byte() = code.toByte()
private fun initTasks() { private fun initTasks() {
receiverTask = AsyncTaskUtil.AsyncTask.make( receiverTask = AsyncTaskUtil.AsyncTask.make(
doInBackground = { doInBackground = {
@ -693,10 +558,10 @@ class MainActivity : AppCompatActivity() {
try { try {
val dataSize = mTCPSocket.getInputStream().read(buffer, 0, 256) val dataSize = mTCPSocket.getInputStream().read(buffer, 0, 256)
if (dataSize >= 3) { if (dataSize >= 3) {
if (dataSize >= 100 && buffer[1] == 'L'.byte() && buffer[2] == 'E'.byte() && buffer[3] == 'D'.byte()) { if (dataSize >= 100 && buffer[1] == 'L'.toByte() && buffer[2] == 'E'.toByte() && buffer[3] == 'D'.toByte()) {
setLED(buffer) setLED(buffer)
} }
if (dataSize >= 4 && buffer[1] == 'P'.byte() && buffer[2] == 'O'.byte() && buffer[3] == 'N'.byte()) { if (dataSize >= 4 && buffer[1] == 'P'.toByte() && buffer[2] == 'O'.toByte() && buffer[3] == 'N'.toByte()) {
val delay = calculateDelay(buffer) val delay = calculateDelay(buffer)
if (delay > 0f) if (delay > 0f)
mCurrentDelay = delay mCurrentDelay = delay
@ -731,10 +596,10 @@ class MainActivity : AppCompatActivity() {
if (packet.address.hostAddress == address.toHostString() && packet.port == address.port) { if (packet.address.hostAddress == address.toHostString() && packet.port == address.port) {
val data = packet.data val data = packet.data
if (data.size >= 3) { if (data.size >= 3) {
if (data.size >= 100 && data[1] == 'L'.byte() && data[2] == 'E'.byte() && data[3] == 'D'.byte()) { if (data.size >= 100 && data[1] == 'L'.toByte() && data[2] == 'E'.toByte() && data[3] == 'D'.toByte()) {
setLED(data) setLED(data)
} }
if (data.size >= 4 && data[1] == 'P'.byte() && data[2] == 'O'.byte() && data[3] == 'N'.byte()) { if (data.size >= 4 && data[1] == 'P'.toByte() && data[2] == 'O'.toByte() && data[3] == 'N'.toByte()) {
val delay = calculateDelay(data) val delay = calculateDelay(data)
if (delay > 0f) if (delay > 0f)
mCurrentDelay = delay mCurrentDelay = delay
@ -769,8 +634,6 @@ class MainActivity : AppCompatActivity() {
val buffer = applyKeys(buttons, IoBuffer()) val buffer = applyKeys(buttons, IoBuffer())
try { try {
mTCPSocket.getOutputStream().write(constructBuffer(buffer)) mTCPSocket.getOutputStream().write(constructBuffer(buffer))
if (mEnableNFC)
mTCPSocket.getOutputStream().write(constructCardData())
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
continue continue
@ -802,8 +665,6 @@ class MainActivity : AppCompatActivity() {
val packet = constructPacket(buffer) val packet = constructPacket(buffer)
try { try {
socket.send(packet) socket.send(packet)
if (mEnableNFC)
socket.send(constructCardPacket())
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
Thread.sleep(100) Thread.sleep(100)
@ -846,7 +707,6 @@ class MainActivity : AppCompatActivity() {
) )
} }
@Suppress("unused")
enum class FunctionButton { enum class FunctionButton {
UNDEFINED, FUNCTION_COIN, FUNCTION_CARD UNDEFINED, FUNCTION_COIN, FUNCTION_CARD
} }
@ -860,7 +720,7 @@ class MainActivity : AppCompatActivity() {
var serviceBtn = false var serviceBtn = false
} }
private fun getLocalIPAddress(useIPv4: Boolean = true): ByteArray { private fun getLocalIPAddress(useIPv4: Boolean): ByteArray {
try { try {
val interfaces: List<NetworkInterface> = Collections.list(NetworkInterface.getNetworkInterfaces()) val interfaces: List<NetworkInterface> = Collections.list(NetworkInterface.getNetworkInterfaces())
for (intf in interfaces) { for (intf in interfaces) {
@ -884,10 +744,10 @@ class MainActivity : AppCompatActivity() {
private fun sendConnect(address: InetSocketAddress?) { private fun sendConnect(address: InetSocketAddress?) {
address ?: return address ?: return
thread { thread {
val selfAddress = getLocalIPAddress() val selfAddress = getLocalIPAddress(true)
if (selfAddress.isEmpty()) return@thread if (selfAddress.isEmpty()) return@thread
val buffer = ByteArray(21) val buffer = ByteArray(21)
byteArrayOf('C'.byte(), 'O'.byte(), 'N'.byte()).copyInto(buffer, 1) byteArrayOf('C'.toByte(), 'O'.toByte(), 'N'.toByte()).copyInto(buffer, 1)
ByteBuffer.wrap(buffer) ByteBuffer.wrap(buffer)
.put(4, if (selfAddress.size == 4) 1.toByte() else 2.toByte()) .put(4, if (selfAddress.size == 4) 1.toByte() else 2.toByte())
.putShort(5, serverPort.toShort()) .putShort(5, serverPort.toShort())
@ -910,7 +770,7 @@ class MainActivity : AppCompatActivity() {
private fun sendDisconnect(address: InetSocketAddress?) { private fun sendDisconnect(address: InetSocketAddress?) {
address ?: return address ?: return
thread { thread {
val buffer = byteArrayOf(3, 'D'.byte(), 'I'.byte(), 'S'.byte()) val buffer = byteArrayOf(3, 'D'.toByte(), 'I'.toByte(), 'S'.toByte())
if (mTCPMode) { if (mTCPMode) {
try { try {
mTCPSocket.getOutputStream().write(buffer) mTCPSocket.getOutputStream().write(buffer)
@ -937,7 +797,7 @@ class MainActivity : AppCompatActivity() {
private fun sendFunctionKey(address: InetSocketAddress?, function: FunctionButton) { private fun sendFunctionKey(address: InetSocketAddress?, function: FunctionButton) {
address ?: return address ?: return
thread { thread {
val buffer = byteArrayOf(4, 'F'.byte(), 'N'.byte(), 'C'.byte(), function.ordinal.toByte()) val buffer = byteArrayOf(4, 'F'.toByte(), 'N'.toByte(), 'C'.toByte(), function.ordinal.toByte())
if (mTCPMode) { if (mTCPMode) {
try { try {
mTCPSocket.getOutputStream().write(buffer) mTCPSocket.getOutputStream().write(buffer)
@ -967,7 +827,7 @@ class MainActivity : AppCompatActivity() {
if (System.currentTimeMillis() - lastPingTime < pingInterval) return if (System.currentTimeMillis() - lastPingTime < pingInterval) return
lastPingTime = System.currentTimeMillis() lastPingTime = System.currentTimeMillis()
val buffer = ByteArray(12) val buffer = ByteArray(12)
byteArrayOf(11, 'P'.byte(), 'I'.byte(), 'N'.byte()).copyInto(buffer) byteArrayOf(11, 'P'.toByte(), 'I'.toByte(), 'N'.toByte()).copyInto(buffer)
ByteBuffer.wrap(buffer, 4, 8).putLong(SystemClock.elapsedRealtimeNanos()) ByteBuffer.wrap(buffer, 4, 8).putLong(SystemClock.elapsedRealtimeNanos())
try { try {
val socket = DatagramSocket() val socket = DatagramSocket()
@ -986,7 +846,7 @@ class MainActivity : AppCompatActivity() {
if (System.currentTimeMillis() - lastPingTime < pingInterval) return if (System.currentTimeMillis() - lastPingTime < pingInterval) return
lastPingTime = System.currentTimeMillis() lastPingTime = System.currentTimeMillis()
val buffer = ByteArray(12) val buffer = ByteArray(12)
byteArrayOf(11, 'P'.byte(), 'I'.byte(), 'N'.byte()).copyInto(buffer) byteArrayOf(11, 'P'.toByte(), 'I'.toByte(), 'N'.toByte()).copyInto(buffer)
ByteBuffer.wrap(buffer, 4, 8).putLong(SystemClock.elapsedRealtimeNanos()) ByteBuffer.wrap(buffer, 4, 8).putLong(SystemClock.elapsedRealtimeNanos())
try { try {
mTCPSocket.getOutputStream().write(buffer) mTCPSocket.getOutputStream().write(buffer)
@ -1013,7 +873,7 @@ class MainActivity : AppCompatActivity() {
realBuf[46] = if (buffer.testBtn) 0x01 else 0x00 realBuf[46] = if (buffer.testBtn) 0x01 else 0x00
realBuf[47] = if (buffer.serviceBtn) 0x01 else 0x00 realBuf[47] = if (buffer.serviceBtn) 0x01 else 0x00
} else { } else {
buffer.slider.copyInto(realBuf, 8) buffer.slider.copyInto(realBuf, 10)
realBuf[40] = if (buffer.testBtn) 0x01 else 0x00 realBuf[40] = if (buffer.testBtn) 0x01 else 0x00
realBuf[41] = if (buffer.serviceBtn) 0x01 else 0x00 realBuf[41] = if (buffer.serviceBtn) 0x01 else 0x00
} }
@ -1025,21 +885,6 @@ class MainActivity : AppCompatActivity() {
return DatagramPacket(realBuf, buffer.length + 1) return DatagramPacket(realBuf, buffer.length + 1)
} }
private fun constructCardData(): ByteArray {
val buf = ByteArray(24)
byteArrayOf(15, 'C'.byte(), 'R'.byte(), 'D'.byte()).copyInto(buf)
buf[4] = if (hasCard) 1 else 0
buf[5] = cardType.ordinal.toByte()
if (hasCard)
cardId.copyInto(buf, 6)
return buf
}
private fun constructCardPacket(): DatagramPacket {
val buf = constructCardData()
return DatagramPacket(buf, buf[0] + 1)
}
private val airUpdateInterval = 10L private val airUpdateInterval = 10L
private var mLastAirHeight = 6 private var mLastAirHeight = 6
private var mLastAirUpdateTime = 0L private var mLastAirUpdateTime = 0L
@ -1047,10 +892,10 @@ class MainActivity : AppCompatActivity() {
return buffer.apply { return buffer.apply {
if (mEnableAir) { if (mEnableAir) {
buffer.length = 47 buffer.length = 47
buffer.header = byteArrayOf('I'.byte(), 'N'.byte(), 'P'.byte()) buffer.header = byteArrayOf('I'.toByte(), 'N'.toByte(), 'P'.toByte())
} else { } else {
buffer.length = 41 buffer.length = 41
buffer.header = byteArrayOf('I'.byte(), 'P'.byte(), 'T'.byte()) buffer.header = byteArrayOf('I'.toByte(), 'P'.toByte(), 'T'.toByte())
} }
if (event.keys != null && event.keys.isNotEmpty()) { if (event.keys != null && event.keys.isNotEmpty()) {
@ -1099,14 +944,12 @@ class MainActivity : AppCompatActivity() {
else -> continue else -> continue
} }
val right = left + width val right = left + width
mLEDCanvas.drawRect(left, 0f, right, drawHeight.toFloat(), color.toPaint()) mLEDCanvas.drawRect(left, 0f, right, drawHeight.toFloat(), makePaint(color.toInt()))
drawXOffset += width drawXOffset += width
} }
mButtonRenderer.postInvalidate() mButtonRenderer.postInvalidate()
} }
private fun Long.toPaint(): Paint = Paint().apply { color = toInt() } private fun makePaint(color: Int): Paint {
return Paint().apply { this.color = color }
companion object {
private const val TAG = "Brokenithm"
} }
} }

View File

@ -1,14 +0,0 @@
package com.github.brokenithm.activity
import android.os.Bundle
import androidx.fragment.app.FragmentActivity
import com.github.brokenithm.R
import com.github.brokenithm.fragment.SettingsFragment
class SettingsActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
supportFragmentManager.beginTransaction().replace(R.id.settings_container, SettingsFragment()).commit()
}
}

View File

@ -1,19 +0,0 @@
package com.github.brokenithm.fragment
import android.os.Bundle
import android.text.InputType
import android.widget.EditText
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceFragmentCompat
import com.github.brokenithm.R
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.sharedPreferencesName = "settings"
setPreferencesFromResource(R.xml.preferences, rootKey)
val setDecimalEdit = { editText: EditText -> editText.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL }
val entries = listOf("fat_touch_threshold", "extra_fat_touch_threshold", "gyro_air_lowest", "gyro_air_highest", "accel_air_threshold")
for (entry in entries)
findPreference<EditTextPreference>(entry)?.setOnBindEditTextListener(setDecimalEdit)
}
}

View File

@ -1,63 +0,0 @@
package com.github.brokenithm.util
import android.nfc.Tag
import android.nfc.tech.NfcF
import android.nfc.tech.TagTechnology
@Suppress("Unused", "MemberVisibilityCanBePrivate", "SpellCheckingInspection", "PropertyName")
class FeliCa private constructor(private val nfcF: NfcF) : TagTechnology {
private lateinit var mTag: Tag
var IDm: ByteArray? = null
private set
var PMm: ByteArray? = null
private set
val systemCode: ByteArray
get() = nfcF.systemCode
override fun connect() = nfcF.connect()
override fun isConnected() = nfcF.isConnected
override fun close() {
IDm = null
PMm = null
nfcF.close()
}
override fun getTag() = mTag
fun getMaxTransceiveLength() = nfcF.maxTransceiveLength
fun transceive(data: ByteArray): ByteArray = nfcF.transceive(data)
var timeout: Int
get() = nfcF.timeout
set(value) { nfcF.timeout = value }
private fun checkConnected() {
if (!nfcF.isConnected)
throw IllegalStateException("Call connect() first!")
}
fun poll(systemCode: Int = 0xFFFF, requestCode: Int = 0x01) {
checkConnected()
val buffer = ByteArray(6)
buffer[0] = 6
buffer[1] = FELICA_CMD_POLLING
buffer[2] = ((systemCode shr 8) and 0xff).toByte()
buffer[3] = (systemCode and 0xff).toByte()
buffer[4] = requestCode.toByte()
buffer[5] = 0
val result = nfcF.transceive(buffer)
if (result.size != 18 && result.size != 20)
throw IllegalStateException("Poll FeliCa response incorrect")
IDm = result.copyOfRange(2, 10)
PMm = result.copyOfRange(10, 18)
}
companion object {
private const val FELICA_CMD_POLLING: Byte = 0x00
fun get(tag: Tag): FeliCa? {
val realTag = NfcF.get(tag) ?: return null
return FeliCa(realTag).apply { mTag = tag }
}
}
}

View File

@ -110,6 +110,18 @@
app:layout_constraintStart_toEndOf="@+id/button_coin" app:layout_constraintStart_toEndOf="@+id/button_coin"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/check_enable_air"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@string/enable_air"
android:textColor="@color/white"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@+id/button_card"
app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:id="@+id/text_switch_air" android:id="@+id/text_switch_air"
android:layout_width="90dp" android:layout_width="90dp"
@ -203,15 +215,25 @@
app:layout_constraintStart_toEndOf="@+id/button_service" app:layout_constraintStart_toEndOf="@+id/button_service"
app:layout_constraintTop_toTopOf="@+id/button_service" /> app:layout_constraintTop_toTopOf="@+id/button_service" />
<CheckBox
android:id="@+id/check_vibrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="@string/enable_vibration"
android:textColor="@color/white"
app:layout_constraintStart_toEndOf="@+id/check_show_delay"
app:layout_constraintTop_toTopOf="@+id/check_show_delay" />
<CheckBox <CheckBox
android:id="@+id/check_simple_air" android:id="@+id/check_simple_air"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="@string/simple_air" android:text="@string/simple_air"
android:textColor="@color/white" android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="@+id/check_show_delay" app:layout_constraintStart_toEndOf="@+id/check_vibrate"
app:layout_constraintStart_toEndOf="@+id/check_show_delay" app:layout_constraintTop_toTopOf="@+id/check_vibrate" />
app:layout_constraintTop_toTopOf="@+id/check_show_delay" />
<TextView <TextView
android:id="@+id/text_mode" android:id="@+id/text_mode"
@ -231,16 +253,6 @@
app:layout_constraintStart_toEndOf="@+id/check_simple_air" app:layout_constraintStart_toEndOf="@+id/check_simple_air"
app:layout_constraintTop_toTopOf="@+id/check_simple_air" /> app:layout_constraintTop_toTopOf="@+id/check_simple_air" />
<Button
android:id="@+id/button_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="@string/settings"
app:layout_constraintBottom_toBottomOf="@+id/text_mode"
app:layout_constraintStart_toEndOf="@+id/text_mode"
app:layout_constraintTop_toTopOf="@+id/text_mode" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</net.cachapa.expandablelayout.ExpandableLayout> </net.cachapa.expandablelayout.ExpandableLayout>

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#202020"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/text_title2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:text="Brokenithm-Evolved Settings"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:id="@+id/settings_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/layout_top">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -27,14 +27,4 @@
<string name="accel_air">Accel Air</string> <string name="accel_air">Accel Air</string>
<string name="touch_air">Touch Air</string> <string name="touch_air">Touch Air</string>
<string name="enable_air">Enable Air</string> <string name="enable_air">Enable Air</string>
<string name="settings">Settings</string>
<string name="gyro_air_highest">Gyro Air Highest Bound</string>
<string name="accel_air_threshold">Accel Air Threshold</string>
<string name="gyro_air_lowest">Gyro Air Lowest Bound</string>
<string name="extra_fat_touch_threshold">Extra Fat Touch Threshold</string>
<string name="fat_touch_threshold">Fat Touch Threshold</string>
<string name="enable_touch_size">Enable Touch Size Check</string>
<string name="enable_nfc">Enable NFC</string>
<string name="enable_vibrate">Enable Vibration</string>
</resources> </resources>

View File

@ -1,9 +0,0 @@
<?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>android.nfc.tech.NfcF</tech>
<tech>android.nfc.tech.NdefFormatable</tech>
<tech>android.nfc.tech.MifareClassic</tech>
</tech-list>
</resources>

View File

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="Common">
<CheckBoxPreference
android:defaultValue="true"
android:key="enable_vibrate"
android:title="@string/enable_vibrate" />
<CheckBoxPreference
android:defaultValue="true"
android:key="enable_nfc"
android:title="@string/enable_nfc" />
</PreferenceCategory>
<PreferenceCategory android:title="Touch Judge">
<CheckBoxPreference
android:defaultValue="false"
android:key="enable_touch_size"
android:title="@string/enable_touch_size" />
<EditTextPreference
android:defaultValue="0.027"
android:key="fat_touch_threshold"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/fat_touch_threshold" />
<EditTextPreference
android:defaultValue="0.035"
android:key="extra_fat_touch_threshold"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/extra_fat_touch_threshold" />
</PreferenceCategory>
<PreferenceCategory android:title="Sensor">
<EditTextPreference
android:defaultValue="0.8"
android:key="gyro_air_lowest"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/gyro_air_lowest" />
<EditTextPreference
android:defaultValue="1.35"
android:key="gyro_air_highest"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/gyro_air_highest" />
<EditTextPreference
android:defaultValue="2.0"
android:key="accel_air_threshold"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/accel_air_threshold" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -1,12 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = "1.5.21" ext.kotlin_version = "1.4.30"
repositories { repositories {
google() google()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.2.2' classpath "com.android.tools.build:gradle:4.1.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip