Compare commits

...
21 Commits
Author SHA1 Message Date
Markus Fisch 47d5923a04 Advance version number to 1.14.0 2019-09-08 21:19:52 +02:00
Markus Fisch 8c22a8ab00 Apply auto formatting 2019-09-08 21:15:12 +02:00
molikunerandMarkus Fisch 8152cb6a24 Add OTP support 2019-09-08 21:06:05 +02:00
zmniandMarkus Fisch ffed4fc5cf Update Indonesian translation 2019-09-04 16:47:56 +02:00
Markus Fisch d8bd3c1176 Advance version number to 1.13.1 2019-08-31 10:45:02 +02:00
molikunerandMarkus Fisch 3b12aa4b7b Fix crash caused by missing \R support for Regex (#62)
* Fix crash caused by missing `\R` support for Regex
* Replaced `\R` usage in VType actions with official equivalent
* Replace `\R`, which was overlooked
2019-08-31 10:38:08 +02:00
Markus Fisch 099b522d35 Advance version number to 1.13.0 2019-08-23 18:32:03 +02:00
Markus Fisch 166d181469 Optimize imports according to Android Studio
Order of imports doesn't matter so I should simply let
Android Studio have its way.
2019-08-23 17:57:17 +02:00
Markus Fisch a4a2a67177 Add missing extras for ZXing result intents
Turns out, some apps do actually use them.
2019-08-23 17:55:39 +02:00
Markus Fisch 7fe3de78af Add screenshots to README 2019-08-09 14:05:28 +02:00
Markus Fisch e75d658092 Advance version number to 1.12.0 2019-08-05 20:29:16 +02:00
Markus Fisch c840462fa2 Fix folder name for Brazilian Portuguese
According to lint, it must read `values-pt-rBR`.
2019-08-05 20:25:51 +02:00
Ivan AmaroandMarkus Fisch c3475a37d2 Add Brazilian Portuguese translation 2019-08-05 14:03:19 +02:00
yzqzssandMarkus Fisch 183fe2c6f2 Add Simplified Chinese 2019-08-04 23:58:00 +02:00
ThomasandMarkus Fisch 056f5e263e Add Chinese translation
This set of Chinese translation is good for zh, zh-Hant, zh-TW, zh-HK and other zh variants. Some English nouns are kept as they are well known in common conversations.

Many app handle Chinese localization pickings differently (with a ton of political dicisions), but in general label this as "中文"/"Chinese" or "正體中文"/“traditional Chinese”.
2019-08-04 23:57:08 +02:00
Markus Fisch 386c7a6056 Encode text using UTF-8 encoding 2019-08-04 23:55:15 +02:00
Markus Fisch 80c876f35d Update description in README
With all the new features it's probably no longer fitting to
say that it doesn't do _anything_ else but decoding a barcode.
2019-07-31 13:19:07 +02:00
Markus Fisch 30ae51d945 Suppress lint warning about null root layout
Because dialogs don't have a parent layout and must
therefore be inflated with a null root layout.
2019-07-31 13:15:28 +02:00
Markus Fisch 95b54ed4ab Add some line breaks
Improves readability (for me).
2019-07-31 13:05:10 +02:00
Markus Fisch 3650bda107 Save preferences when leaving fragment only
Much simpler.
2019-07-30 13:48:19 +02:00
Markus Fisch 2bdf13761e Add preferences and the option to use a custom URL
For opening unknown barcodes. Should close #48.
2019-07-28 13:59:42 +02:00
51 changed files with 833 additions and 214 deletions
+16
View File
@@ -1,5 +1,21 @@
# Change Log
# 1.14.0
* Add OTP support
* Update Indonesian translation
# 1.13.1
* Fix crash caused by missing support for Regex on Android < 6
# 1.13.0
* Add missing extras for ZXing result intents
# 1.12.0
* Add preferences dialog and the option to use a custom URL with read contents
* Add Brazilian Portuguese translation
* Add Chinese translation
* Encode text using UTF-8 encoding when creating a barcode
# 1.11.2
* Downgrade ZXing version
* Improve getting system UI metrics
+18 -4
View File
@@ -5,15 +5,29 @@ Yet another barcode scanner for Android. As if there weren't [enough][play].
This one is totally free, open source and does use the [ZXing][zxing] barcode
scanning library.
Unlike many others it works in portrait and landscape orientation, can read
inverted codes, uses Material Design and doesn't do anything else but decoding
Unlike many others, it works in portrait and landscape orientation, can read
inverted codes, comes in Material Design and doesn't do much else but decoding
a barcode.
<a href="https://f-droid.org/en/packages/de.markusfisch.android.binaryeye/"><img alt="Get it on F-Droid" src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="80"/></a> <a href="https://play.google.com/store/apps/details?id=de.markusfisch.android.binaryeye"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" height="80"/></a>
And it's written in [Kotlin][kotlin] because I wanted to explore that a
bit more.
## Screenshots
<img
src="https://raw.githubusercontent.com/markusfisch/BinaryEye/gh-pages/screencap-scanning.png"
alt="Screenshot Scanning" width="160"/>
<img
src="https://raw.githubusercontent.com/markusfisch/BinaryEye/gh-pages/screencap-decoded.png"
alt="Screenshot Result" width="160"/>
<img
src="https://raw.githubusercontent.com/markusfisch/BinaryEye/gh-pages/screencap-compose-barcode.png"
alt="Screenshot Compose Barcode" width="160"/>
## Download
<a href="https://f-droid.org/en/packages/de.markusfisch.android.binaryeye/"><img alt="Get it on F-Droid" src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="80"/></a> <a href="https://play.google.com/store/apps/details?id=de.markusfisch.android.binaryeye"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" height="80"/></a>
[play]: https://play.google.com/store/search?q=barcode%20scanner&c=apps
[zxing]: https://github.com/zxing/zxing
[kotlin]: http://kotlinlang.org/
+2 -2
View File
@@ -9,8 +9,8 @@ android {
minSdkVersion 9
targetSdkVersion sdk_version
versionCode 33
versionName '1.11.2'
versionCode 39
versionName '1.14.0'
// it's recommended to set this value to the lowest API level
// able to provide all the functionality
@@ -1,6 +1,7 @@
package de.markusfisch.android.binaryeye.actions
import de.markusfisch.android.binaryeye.actions.mail.MailAction
import de.markusfisch.android.binaryeye.actions.otpauth.OtpauthAction
import de.markusfisch.android.binaryeye.actions.sms.SmsAction
import de.markusfisch.android.binaryeye.actions.tel.TelAction
import de.markusfisch.android.binaryeye.actions.vtype.vcard.VCardAction
@@ -9,7 +10,7 @@ import de.markusfisch.android.binaryeye.actions.wifi.WifiAction
object ActionRegistry {
val REGISTRY: Set<IAction> = setOf(
MailAction, SmsAction, TelAction, VCardAction, VEventAction, WifiAction
MailAction, OtpauthAction, SmsAction, TelAction, VCardAction, VEventAction, WifiAction
)
fun getAction(data: ByteArray): IAction? = REGISTRY.find {
@@ -1,10 +1,9 @@
package de.markusfisch.android.binaryeye.actions
import de.markusfisch.android.binaryeye.app.execShareIntent
import android.content.Context
import android.content.Intent
import android.widget.Toast
import de.markusfisch.android.binaryeye.app.execShareIntent
interface IAction {
val iconResId: Int
@@ -1,11 +1,10 @@
package de.markusfisch.android.binaryeye.actions.mail
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
import android.content.Context
import android.content.Intent
import android.net.Uri
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
object MailAction : SimpleIntentIAction() {
private val mailRegex =
@@ -0,0 +1,22 @@
package de.markusfisch.android.binaryeye.actions.otpauth
import android.content.Context
import android.content.Intent
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
object OtpauthAction : SimpleIntentIAction() {
override val iconResId: Int = R.drawable.ic_action_otpauth
override val titleResId: Int = R.string.otpauth_add
override val errorMsg: Int = R.string.otpauth_error
override fun canExecuteOn(data: ByteArray): Boolean {
return OtpauthParser(String(data)) != null
}
override fun executeForIntent(context: Context, data: ByteArray): Intent? {
return OtpauthParser(String(data))?.let {
Intent(Intent.ACTION_VIEW, it.uri)
}
}
}
@@ -0,0 +1,76 @@
package de.markusfisch.android.binaryeye.actions.otpauth
import android.net.Uri
class OtpauthParser private constructor(private val match: MatchResult) {
val otpType: String
get() = match.groupValues[1]
private val labelIssuer: String
get() = match.groupValues[2]
val accountName: String
get() = match.groupValues[3].takeIf { it.isNotEmpty() } ?: match.groupValues[4]
val secret: String
get() = match.groupValues[5]
private val parameterIssuer: String
get() = match.groupValues[6]
val algorithm: String
get() = match.groupValues[7].takeIf { it.isNotEmpty() } ?: "SHA1"
val digits: Int
get() = match.groupValues[8].toIntOrNull() ?: 6
val period: Int
get() = match.groupValues[9].toIntOrNull() ?: 30
private val parameterCounter: String
get() = match.groupValues[10]
val issuer: String
get() = labelIssuer.takeIf { it.isNotEmpty() } ?: parameterIssuer
val counter: Int
get() = parameterCounter.toInt()
private val isHotp: Boolean = otpType == "hotp"
val isValid: Boolean =
(labelIssuer.isNotEmpty() == parameterIssuer.isEmpty() || labelIssuer.isEmpty())
&& secret.isNotEmpty() && isHotp == parameterCounter.isNotEmpty()
val uri: Uri
get() = Uri.Builder().apply {
scheme("otpauth")
authority(otpType)
if (issuer.isNotEmpty()) {
encodedPath("/$issuer:$accountName")
appendQueryParameter("issuer", issuer)
} else {
encodedPath("/$accountName")
}
appendQueryParameter("secret", secret)
appendQueryParameter("algorithm", algorithm)
appendQueryParameter("digits", digits.toString())
if (isHotp) {
appendQueryParameter("counter", counter.toString())
} else {
appendQueryParameter("period", period.toString())
}
}.build()
companion object {
private const val issuerAndAccount =
"""(?:(?:([^?:]+)(?::|%3A)(?:%20)*([^?]+))|([^?]+))"""//.toRegex()
/** allowing `padding` even though it should not be there, will be removed in output*/
private const val secret = """(?:secret=([2-7A-Z]+)=*)"""//.toRegex()
/** `\2` references the issuer of [issuerAndAccount] */
private const val issuer = """(?:issuer=\2)|(?:issuer=([^&]+))"""//.toRegex()
private const val algorithm = """(?:algorithm=(SHA(?:1|256|512)))"""//.toRegex()
private const val digits = """(?:digits=([0-9]+))"""//.toRegex()
private const val period = """(?:period=([0-9]+))"""//.toRegex()
private const val counter = """(?:counter=([0-9]+))"""//.toRegex()
private val otpauthRegex =
"""^otpauth://([ht]otp)/$issuerAndAccount\?(?:&?(?:$secret|$issuer|$algorithm|$digits|$period|$counter))+$""".toRegex(
RegexOption.IGNORE_CASE
)
operator fun invoke(input: String): OtpauthParser? {
return otpauthRegex.matchEntire(input)?.let(::OtpauthParser)?.takeIf { it.isValid }
}
}
}
@@ -1,14 +1,14 @@
package de.markusfisch.android.binaryeye.actions.sms
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
import android.content.Context
import android.content.Intent
import android.net.Uri
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
object SmsAction : SimpleIntentIAction() {
private val smsRegex = """^sms(?:to)?:(\+?[0-9]+)(?::([\S\s]*))?$""".toRegex(RegexOption.IGNORE_CASE)
private val smsRegex =
"""^sms(?:to)?:(\+?[0-9]+)(?::([\S\s]*))?$""".toRegex(RegexOption.IGNORE_CASE)
override val iconResId: Int = R.drawable.ic_action_sms
override val titleResId: Int = R.string.sms_send
@@ -1,11 +1,10 @@
package de.markusfisch.android.binaryeye.actions.tel
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
import android.content.Context
import android.content.Intent
import android.net.Uri
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
object TelAction : SimpleIntentIAction() {
private val telRegex = """^tel:(\+?[0-9]+)$""".toRegex(RegexOption.IGNORE_CASE)
@@ -1,11 +1,16 @@
package de.markusfisch.android.binaryeye.actions.vtype
object VTypeParser {
private const val BACKSLASH_R_LEGACY =
"(?:\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029])"
private val vTypeRegex =
"""^BEGIN:(VCARD|VEVENT)(?:\R.+?:[\s\S]+?)+?\REND:\1\R?$""".toRegex(RegexOption.IGNORE_CASE)
"""^BEGIN:(VCARD|VEVENT)(?:$BACKSLASH_R_LEGACY.+?:[\s\S]+?)+?${BACKSLASH_R_LEGACY}END:\1$BACKSLASH_R_LEGACY?$""".toRegex(
RegexOption.IGNORE_CASE
)
private val propertyRegex = """^(.+?):([\s\S]*?)$""".toRegex(RegexOption.MULTILINE)
fun parseVType(data: String): String? = vTypeRegex.matchEntire(data)?.groupValues?.get(1)?.toUpperCase()
fun parseVType(data: String): String? =
vTypeRegex.matchEntire(data)?.groupValues?.get(1)?.toUpperCase()
fun parseMap(data: String): Map<String, List<VTypeProperty>> = propertyRegex.findAll(data).map {
it.groupValues[1].split(';').let { typeAndInfo ->
@@ -1,14 +1,13 @@
package de.markusfisch.android.binaryeye.actions.vtype.vcard
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
import de.markusfisch.android.binaryeye.actions.vtype.VTypeParser
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.os.Build
import android.provider.ContactsContract
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
import de.markusfisch.android.binaryeye.actions.vtype.VTypeParser
object VCardAction : SimpleIntentIAction() {
override val iconResId: Int
@@ -116,14 +115,23 @@ object VCardAction : SimpleIntentIAction() {
}
private val String.locationFormat: String
get() = """^([^;]*?);([^;]*?);([^;]*?);([^;]*?);([^;]*?);([^;]*?);([^;]*?)$""".toRegex().matchEntire(this)?.groupValues?.let {
listOf(it[1], it[2], it[3], "${it[4]} ${it[6]}", "${it[5]} ${it[7]}").filter { line -> line.isNotBlank() }
get() = """^([^;]*?);([^;]*?);([^;]*?);([^;]*?);([^;]*?);([^;]*?);([^;]*?)$""".toRegex().matchEntire(
this
)?.groupValues?.let {
listOf(
it[1],
it[2],
it[3],
"${it[4]} ${it[6]}",
"${it[5]} ${it[7]}"
).filter { line -> line.isNotBlank() }
.joinToString("\n").takeIf { location -> location.isNotBlank() }
} ?: this
private val String.nameFormat: String
get() = """^([^;]*?);([^;]*?);([^;]*?);([^;]*?);([^;]*?)$""".toRegex().matchEntire(this)?.groupValues?.let {
listOf(it[4], it[2], it[3], it[1], it[5]).joinToString(" ").takeIf { name -> name.isNotBlank() }
listOf(it[4], it[2], it[3], it[1], it[5]).joinToString(" ")
.takeIf { name -> name.isNotBlank() }
} ?: this
private val String.mailType: Int?
@@ -1,18 +1,16 @@
package de.markusfisch.android.binaryeye.actions.vtype.vevent
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
import de.markusfisch.android.binaryeye.actions.vtype.VTypeParser
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Build
import android.provider.CalendarContract
import android.support.annotation.RequiresApi
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
import de.markusfisch.android.binaryeye.actions.vtype.VTypeParser
import java.text.SimpleDateFormat
import java.util.Date
import java.util.*
object VEventAction : SimpleIntentIAction() {
override val iconResId: Int
@@ -1,19 +1,13 @@
package de.markusfisch.android.binaryeye.actions.wifi
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.IAction
import android.content.Context
import android.content.Context.WIFI_SERVICE
import android.net.wifi.WifiConfiguration
import android.net.wifi.WifiManager
import android.widget.Toast
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.IAction
import kotlinx.coroutines.*
object WifiAction : IAction {
override val iconResId = R.drawable.ic_action_wifi
@@ -194,8 +194,10 @@ object WifiConfigurationFactory {
enterpriseConfig.identity = data.identity
enterpriseConfig.anonymousIdentity = data.anonymousIdentity
enterpriseConfig.password = data.password
enterpriseConfig.eapMethod = data.eapMethod ?: return null // non valid eapMethod
enterpriseConfig.phase2Method = data.phase2Method ?: return null // non valid phase2Method
enterpriseConfig.eapMethod =
data.eapMethod ?: return null // non valid eapMethod
enterpriseConfig.phase2Method =
data.phase2Method ?: return null // non valid phase2Method
} ?: return null // api isn't high enough
}
return this
@@ -1,18 +1,5 @@
package de.markusfisch.android.binaryeye.activity
import com.google.zxing.Result
import com.google.zxing.ResultMetadataType
import de.markusfisch.android.cameraview.widget.CameraView
import de.markusfisch.android.binaryeye.app.db
import de.markusfisch.android.binaryeye.app.hasCameraPermission
import de.markusfisch.android.binaryeye.app.initSystemBars
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.rs.Preprocessor
import de.markusfisch.android.binaryeye.zxing.Zxing
import de.markusfisch.android.binaryeye.R
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -30,10 +17,18 @@ import android.view.MenuItem
import android.view.View
import android.widget.SeekBar
import android.widget.Toast
import com.google.zxing.Result
import com.google.zxing.ResultMetadataType
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.db
import de.markusfisch.android.binaryeye.app.hasCameraPermission
import de.markusfisch.android.binaryeye.app.initSystemBars
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.rs.Preprocessor
import de.markusfisch.android.binaryeye.zxing.Zxing
import de.markusfisch.android.cameraview.widget.CameraView
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.IOException
class CameraActivity : AppCompatActivity() {
@@ -165,6 +160,10 @@ class CameraActivity : AppCompatActivity() {
switchCamera()
true
}
R.id.preferences -> {
startActivity(MainActivity.getPreferencesIntent(this))
true
}
R.id.info -> {
openReadme()
true
@@ -409,9 +408,7 @@ class CameraActivity : AppCompatActivity() {
}
if (returnResult) {
val resultIntent = Intent()
resultIntent.putExtra("SCAN_RESULT", result.text)
setResult(RESULT_OK, resultIntent)
setResult(RESULT_OK, getReturnIntent(result))
finish()
return
}
@@ -462,7 +459,53 @@ fun getRawBytes(result: Result): ByteArray? {
for (seg in segments as Iterable<ByteArray>) {
bytes += seg
}
// byte segments can never be shorter than the text;
// byte segments can never be shorter than the text.
// Zxing cuts off content prefixes like "WIFI:"
return if (bytes.size >= result.text.length) bytes else null
}
fun getReturnIntent(result: Result): Intent {
val intent = Intent()
intent.putExtra("SCAN_RESULT", result.text)
intent.putExtra(
"SCAN_RESULT_FORMAT",
result.barcodeFormat.toString()
)
if (result.rawBytes?.isNotEmpty() == true) {
intent.putExtra("SCAN_RESULT_BYTES", result.rawBytes)
}
val metadata = result.resultMetadata
metadata?.let {
val orientation = metadata[ResultMetadataType.UPC_EAN_EXTENSION]
orientation?.let {
intent.putExtra(
"SCAN_RESULT_ORIENTATION",
orientation.toString()
)
}
val ecLevel = metadata[ResultMetadataType.ERROR_CORRECTION_LEVEL]
ecLevel?.let {
intent.putExtra(
"SCAN_RESULT_ERROR_CORRECTION_LEVEL",
ecLevel.toString()
)
}
val upcEanExtension = metadata[ResultMetadataType.UPC_EAN_EXTENSION]
upcEanExtension?.let {
intent.putExtra(
"SCAN_RESULT_UPC_EAN_EXTENSION",
upcEanExtension.toString()
)
}
val segments = metadata[ResultMetadataType.BYTE_SEGMENTS]
segments?.let {
var i = 0
@Suppress("UNCHECKED_CAST")
for (seg in segments as Iterable<ByteArray>) {
intent.putExtra("SCAN_RESULT_BYTE_SEGMENTS_$i", seg)
++i
}
}
}
return intent
}
@@ -1,20 +1,19 @@
package de.markusfisch.android.binaryeye.activity
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.initSystemBars
import de.markusfisch.android.binaryeye.app.setFragment
import de.markusfisch.android.binaryeye.fragment.DecodeFragment
import de.markusfisch.android.binaryeye.fragment.EncodeFragment
import de.markusfisch.android.binaryeye.fragment.HistoryFragment
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.initSystemBars
import de.markusfisch.android.binaryeye.app.setFragment
import de.markusfisch.android.binaryeye.fragment.DecodeFragment
import de.markusfisch.android.binaryeye.fragment.EncodeFragment
import de.markusfisch.android.binaryeye.fragment.HistoryFragment
import de.markusfisch.android.binaryeye.fragment.PreferencesFragment
class MainActivity : AppCompatActivity() {
override fun onSupportNavigateUp(): Boolean {
@@ -38,17 +37,22 @@ class MainActivity : AppCompatActivity() {
if (state == null) {
setFragment(
supportFragmentManager, when {
intent?.hasExtra(HISTORY) == true -> HistoryFragment()
intent?.hasExtra(ENCODE) == true -> EncodeFragment.newInstance(
intent.getStringExtra(ENCODE)
)
intent?.hasExtra(DECODED_TEXT) == true -> DecodeFragment.newInstance(
intent.getStringExtra(DECODED_TEXT),
intent.getSerializableExtra(
DECODED_FORMAT
) as BarcodeFormat,
intent.getByteArrayExtra(DECODED_RAW)
)
intent?.hasExtra(PREFERENCES) == true ->
PreferencesFragment()
intent?.hasExtra(HISTORY) == true ->
HistoryFragment()
intent?.hasExtra(ENCODE) == true ->
EncodeFragment.newInstance(
intent.getStringExtra(ENCODE)
)
intent?.hasExtra(DECODED_TEXT) == true ->
DecodeFragment.newInstance(
intent.getStringExtra(DECODED_TEXT),
intent.getSerializableExtra(
DECODED_FORMAT
) as BarcodeFormat,
intent.getByteArrayExtra(DECODED_RAW)
)
else -> DecodeFragment()
}
)
@@ -56,12 +60,19 @@ class MainActivity : AppCompatActivity() {
}
companion object {
private const val PREFERENCES = "preferences"
private const val HISTORY = "history"
private const val ENCODE = "encode"
private const val DECODED_TEXT = "decoded_text"
private const val DECODED_FORMAT = "decoded_format"
private const val DECODED_RAW = "decoded_raw"
fun getPreferencesIntent(context: Context): Intent {
val intent = Intent(context, MainActivity::class.java)
intent.putExtra(PREFERENCES, true)
return intent
}
fun getHistoryIntent(context: Context): Intent {
val intent = Intent(context, MainActivity::class.java)
intent.putExtra(HISTORY, true)
@@ -76,9 +87,10 @@ class MainActivity : AppCompatActivity() {
val intent = Intent(context, MainActivity::class.java)
intent.putExtra(ENCODE, text)
if (isExternal) {
val flagActivityClearTask = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
Intent.FLAG_ACTIVITY_CLEAR_TASK
} else 0
val flagActivityClearTask =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
Intent.FLAG_ACTIVITY_CLEAR_TASK
} else 0
intent.addFlags(
Intent.FLAG_ACTIVITY_NO_HISTORY or
flagActivityClearTask or
@@ -1,8 +1,5 @@
package de.markusfisch.android.binaryeye.adapter
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.data.Database
import android.content.Context
import android.database.Cursor
import android.view.LayoutInflater
@@ -10,6 +7,8 @@ import android.view.View
import android.view.ViewGroup
import android.widget.CursorAdapter
import android.widget.TextView
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.data.Database
class ScansAdapter(context: Context, cursor: Cursor) :
CursorAdapter(context, cursor, false) {
@@ -1,10 +1,9 @@
package de.markusfisch.android.binaryeye.app
import de.markusfisch.android.binaryeye.data.Database
import de.markusfisch.android.binaryeye.preference.Preferences
import android.app.Application
import android.support.v8.renderscript.RenderScript
import de.markusfisch.android.binaryeye.data.Database
import de.markusfisch.android.binaryeye.preference.Preferences
val db = Database()
val prefs = Preferences()
@@ -1,11 +1,10 @@
package de.markusfisch.android.binaryeye.app
import de.markusfisch.android.binaryeye.R
import android.annotation.SuppressLint
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentTransaction
import de.markusfisch.android.binaryeye.R
fun setFragment(fm: FragmentManager?, fragment: Fragment) {
fm?.let { getTransaction(fm, fragment).commit() }
@@ -1,10 +1,10 @@
package de.markusfisch.android.binaryeye.app
import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.Manifest
fun hasCameraPermission(activity: Activity, requestCode: Int): Boolean {
return hasPermission(activity, Manifest.permission.CAMERA, requestCode)
@@ -1,15 +1,13 @@
package de.markusfisch.android.binaryeye.app
import de.markusfisch.android.binaryeye.BuildConfig
import de.markusfisch.android.binaryeye.R
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.support.v4.content.FileProvider
import android.widget.Toast
import de.markusfisch.android.binaryeye.BuildConfig
import de.markusfisch.android.binaryeye.R
import java.io.File
fun shareText(context: Context, text: String, type: String = "text/plain") {
@@ -1,13 +1,12 @@
package de.markusfisch.android.binaryeye.app
import de.markusfisch.android.binaryeye.R
import android.os.Build
import android.support.v4.content.ContextCompat
import android.support.v4.view.ViewCompat
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.view.Window
import de.markusfisch.android.binaryeye.R
fun initSystemBars(activity: AppCompatActivity?) {
val view = activity?.findViewById(R.id.main_layout) ?: return
@@ -40,7 +39,7 @@ fun setSystemBarColor(window: Window, color: Int): Boolean {
window.navigationBarColor = color
window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
return true
}
@@ -1,13 +1,12 @@
package de.markusfisch.android.binaryeye.data
import de.markusfisch.android.binaryeye.app.hasNonPrintableCharacters
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.text.format.DateFormat
import de.markusfisch.android.binaryeye.app.hasNonPrintableCharacters
class Database {
private lateinit var db: SQLiteDatabase
@@ -1,27 +1,23 @@
package de.markusfisch.android.binaryeye.fragment
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.app.shareFile
import de.markusfisch.android.binaryeye.zxing.Zxing
import de.markusfisch.android.binaryeye.R
import android.os.Bundle
import android.graphics.Bitmap
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.shareFile
import de.markusfisch.android.binaryeye.zxing.Zxing
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
class BarcodeFragment : Fragment() {
override fun onCreateView(
@@ -1,15 +1,6 @@
package de.markusfisch.android.binaryeye.fragment
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.IAction
import de.markusfisch.android.binaryeye.actions.validateOrGetNew
import de.markusfisch.android.binaryeye.app.addFragment
import de.markusfisch.android.binaryeye.app.hasNonPrintableCharacters
import de.markusfisch.android.binaryeye.app.hasWritePermission
import de.markusfisch.android.binaryeye.app.shareText
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.content.Intent
@@ -21,17 +12,16 @@ import android.support.v4.app.Fragment
import android.text.ClipboardManager
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.*
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.IAction
import de.markusfisch.android.binaryeye.actions.validateOrGetNew
import de.markusfisch.android.binaryeye.app.*
import java.io.File
import java.io.IOException
import java.net.URLEncoder
@@ -211,12 +201,19 @@ class DecodeFragment : Fragment() {
}
private fun pickSearchEngineAndSearch(context: Context, query: String) {
val names = context.resources.getStringArray(
R.array.search_engines_names
).toMutableList()
val urls = context.resources.getStringArray(
R.array.search_engines_values
)
).toMutableList()
if (prefs.openWithUrl.isNotEmpty()) {
names.add(prefs.openWithUrl)
urls.add(prefs.openWithUrl)
}
AlertDialog.Builder(context)
.setTitle(R.string.pick_search_engine)
.setItems(R.array.search_engines_names) { _, which ->
.setItems(names.toTypedArray()) { _, which ->
openUrl(
urls[which] + URLEncoder.encode(query, "utf-8"),
executeCustomAction = false,
@@ -226,6 +223,9 @@ class DecodeFragment : Fragment() {
.show()
}
// dialogs don't have a parent layout and must therefore be
// inflated with a null root layout
@SuppressLint("InflateParams")
private fun askForFileNameAndSave(raw: ByteArray) {
val ac = activity ?: return
val view = ac.layoutInflater.inflate(R.layout.dialog_save_file, null)
@@ -1,23 +1,16 @@
package de.markusfisch.android.binaryeye.fragment
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.app.addFragment
import de.markusfisch.android.binaryeye.R
import android.content.Context
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.inputmethod.InputMethodManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.SeekBar
import android.widget.Spinner
import android.widget.TextView
import android.widget.Toast
import android.view.inputmethod.InputMethodManager
import android.widget.*
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.addFragment
class EncodeFragment : Fragment() {
private lateinit var formatView: Spinner
@@ -1,28 +1,20 @@
package de.markusfisch.android.binaryeye.fragment
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.adapter.ScansAdapter
import de.markusfisch.android.binaryeye.app.addFragment
import de.markusfisch.android.binaryeye.app.db
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.app.shareText
import de.markusfisch.android.binaryeye.data.Database
import de.markusfisch.android.binaryeye.R
import android.app.AlertDialog
import android.content.Context
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.widget.SwitchCompat
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.*
import android.widget.ListView
import com.google.zxing.BarcodeFormat
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.adapter.ScansAdapter
import de.markusfisch.android.binaryeye.app.addFragment
import de.markusfisch.android.binaryeye.app.db
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.app.shareText
import de.markusfisch.android.binaryeye.data.Database
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@@ -0,0 +1,46 @@
package de.markusfisch.android.binaryeye.fragment
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.widget.SwitchCompat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.prefs
class PreferencesFragment : Fragment() {
private lateinit var useHistorySwitch: SwitchCompat
private lateinit var openWithUrlInput: EditText
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
state: Bundle?
): View? {
activity.setTitle(R.string.preferences)
val view = inflater.inflate(
R.layout.fragment_preferences,
container,
false
)
useHistorySwitch = view.findViewById<SwitchCompat>(R.id.use_history)
if (prefs.useHistory) {
useHistorySwitch.toggle()
}
openWithUrlInput = view.findViewById<EditText>(R.id.open_with_url)
openWithUrlInput.setText(prefs.openWithUrl)
return view
}
override fun onPause() {
super.onPause()
prefs.useHistory = useHistorySwitch.isChecked()
prefs.openWithUrl = openWithUrlInput.text.toString()
}
}
@@ -12,6 +12,11 @@ class Preferences {
setBoolean(USE_HISTORY, value)
field = value
}
var openWithUrl: String = ""
set(value) {
setString(OPEN_WITH_URL, value)
field = value
}
fun init(context: Context) {
preferences = PreferenceManager.getDefaultSharedPreferences(context)
@@ -20,6 +25,7 @@ class Preferences {
fun update() {
useHistory = preferences.getBoolean(USE_HISTORY, useHistory)
openWithUrl = preferences.getString(OPEN_WITH_URL, openWithUrl)
}
private fun setBoolean(label: String, value: Boolean) {
@@ -28,7 +34,14 @@ class Preferences {
editor.apply()
}
private fun setString(label: String, value: String) {
val editor = preferences.edit()
editor.putString(label, value)
editor.apply()
}
companion object {
const val USE_HISTORY = "use_history"
const val OPEN_WITH_URL = "open_with_url"
}
}
@@ -1,13 +1,8 @@
package de.markusfisch.android.binaryeye.rs
import de.markusfisch.android.binaryeye.renderscript.ScriptC_rotator
import android.content.Context
import android.support.v8.renderscript.Allocation
import android.support.v8.renderscript.Element
import android.support.v8.renderscript.RenderScript
import android.support.v8.renderscript.ScriptIntrinsicResize
import android.support.v8.renderscript.Type
import android.support.v8.renderscript.*
import de.markusfisch.android.binaryeye.renderscript.ScriptC_rotator
class Preprocessor(
context: Context,
@@ -1,22 +1,9 @@
package de.markusfisch.android.binaryeye.zxing
import com.google.zxing.BarcodeFormat
import com.google.zxing.BinaryBitmap
import com.google.zxing.DecodeHintType
import com.google.zxing.LuminanceSource
import com.google.zxing.MultiFormatReader
import com.google.zxing.MultiFormatWriter
import com.google.zxing.PlanarYUVLuminanceSource
import com.google.zxing.RGBLuminanceSource
import com.google.zxing.ReaderException
import com.google.zxing.Result
import com.google.zxing.common.HybridBinarizer
import android.graphics.Bitmap
import java.util.Arrays
import java.util.EnumMap
import java.util.EnumSet
import com.google.zxing.*
import com.google.zxing.common.HybridBinarizer
import java.util.*
class Zxing {
private val multiFormatReader: MultiFormatReader = MultiFormatReader()
@@ -137,12 +124,14 @@ class Zxing {
width: Int,
height: Int
): Bitmap? {
val hints = EnumMap<EncodeHintType, Any>(EncodeHintType::class.java)
hints[EncodeHintType.CHARACTER_SET] = "utf-8"
val result = MultiFormatWriter().encode(
text,
format,
width,
height,
null
hints
)
val w = result.width
val h = result.height
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportHeight="24.0"
android:viewportWidth="24.0"
android:width="24dp">
<path android:fillColor="#FF000000"
android:pathData="M14,10L2,10v2h12v-2zM14,6L2,6v2h12L14,6zM18,14v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2,16h8v-2L2,14v2z"/>
</vector>
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z"/>
</vector>
+4 -1
View File
@@ -1,5 +1,6 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -10,9 +11,11 @@
android:layout_marginBottom="8dp"
android:text="@string/save_as_file_name"/>
<EditText
tools:targetApi="o"
android:id="@+id/file_name"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/file_name" />
android:hint="@string/file_name"
android:importantForAutofill="no"/>
</LinearLayout>
@@ -0,0 +1,30 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:orientation="vertical">
<android.support.v7.widget.SwitchCompat
android:id="@+id/use_history"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:text="@string/use_history"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/open_with_url"/>
<EditText
tools:targetApi="o"
android:id="@+id/open_with_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:gravity="start|top"
android:typeface="monospace"
android:imeOptions="flagNoExtractUi"
android:inputType="textUri"
android:hint="@string/open_with_url_hint"
android:importantForAutofill="no"/>
</LinearLayout>
@@ -16,6 +16,11 @@
android:title="@string/switch_camera"
android:icon="@drawable/ic_action_switch_camera"
material:showAsAction="ifRoom"/>
<item
android:id="@+id/preferences"
android:title="@string/preferences"
android:icon="@drawable/ic_action_preferences"
material:showAsAction="ifRoom"/>
<item
android:id="@+id/info"
android:title="@string/info"
+5 -1
View File
@@ -18,7 +18,7 @@
<string name="cannot_resolve_action">Keine App kann das öffnen</string>
<string name="pick_search_engine">Suchmaschine auswählen</string>
<string name="format">Format</string>
<string name="size">Größe in Pixeln</string>
<string name="size">Größe in Pixel</string>
<string name="width_by_height">%1$d×%2$d</string>
<string name="input_content_here">Gib den Inhalt hier ein</string>
<string name="encode">KODIEREN</string>
@@ -28,7 +28,9 @@
<string name="info">Info</string>
<string name="switch_camera">Kamera wechseln</string>
<string name="history">Gespeicherte Codes</string>
<string name="preferences">Einstellungen</string>
<string name="use_history">Codes speichern</string>
<string name="open_with_url">URL zum Öffnen unbekannter Daten</string>
<string name="really_remove_scan">Code wirklich entfernen?</string>
<string name="really_remove_all_scans">Alle Codes entfernen?</string>
<string name="clear_history">Gespeicherte Codes löschen</string>
@@ -53,4 +55,6 @@
<string name="vcard_failed">Konnte nicht zu den Kontakten hinzufügen</string>
<string name="vevent_add">Zum Kalender hinzufügen</string>
<string name="vevent_failed">Konnte nicht zum Kalender hinzufügen</string>
<string name="otpauth_add">2FA hinzufügen</string>
<string name="otpauth_error">Konnte 2FA nicht hinzufügen</string>
</resources>
+4
View File
@@ -28,7 +28,9 @@
<string name="info">Info</string>
<string name="switch_camera">Changer de camera</string>
<string name="history">Historique</string>
<string name="preferences">Preferences</string>
<string name="use_history">Sauvegarder l\'histoire des scans</string>
<string name="open_with_url">Open unknown data with URL</string>
<string name="really_remove_scan">Supprimer le scan ?</string>
<string name="really_remove_all_scans">Supprimer tous les scans ?</string>
<string name="clear_history">Clear history</string>
@@ -53,4 +55,6 @@
<string name="vcard_failed">Could not add to contacts</string>
<string name="vevent_add">Add to calendar</string>
<string name="vevent_failed">Could not add to calendar</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
+4
View File
@@ -28,7 +28,9 @@
<string name="info">Információ</string>
<string name="switch_camera">Kamera átkapcsolása</string>
<string name="history">Előzmények</string>
<string name="preferences">Preferences</string>
<string name="use_history">Beolvasási előzmények mentése</string>
<string name="open_with_url">Open unknown data with URL</string>
<string name="really_remove_scan">Valóban eltávolítja a beolvasást?</string>
<string name="really_remove_all_scans">Valóban eltávolítja az összes beolvasását?</string>
<string name="clear_history">Előzmények törlése</string>
@@ -53,4 +55,6 @@
<string name="vcard_failed">Could not add to contacts</string>
<string name="vevent_add">Add to calendar</string>
<string name="vevent_failed">Could not add to calendar</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
+20 -16
View File
@@ -1,12 +1,12 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="no_camera_no_fun">Aplikasi ini tidak akan bisa bekerja tanpa akses kamera. Selamat tinggal.</string>
<resources>
<string name="no_camera_no_fun">Aplikasi tidak akan bisa bekerja tanpa akses kamera. Selamat tinggal.</string>
<string name="camera_error">Tidak bisa mengakses kamera, silakan coba lagi</string>
<string name="scan_code">Pindai kode</string>
<string name="compose_barcode">Buat barcode</string>
<string name="decode_barcode">Dekode barcode</string>
<string name="content">Konten</string>
<string name="binary_data">(data binari)</string>
<plurals name="barcode_info" tools:ignore="UnusedQuantity">
<plurals name="barcode_info">
<item quantity="one">%1$s\n%2$d karakter</item>
<item quantity="other">%1$s\n%2$d karakter</item>
</plurals>
@@ -28,7 +28,9 @@
<string name="info">Info</string>
<string name="switch_camera">Ganti kamera</string>
<string name="history">Riwayat</string>
<string name="preferences">Preferensi</string>
<string name="use_history">Simpan riwayat pemindaian</string>
<string name="open_with_url">Buka data tak dikenal dengan URL</string>
<string name="really_remove_scan">Yakin menghapus pemindaian?</string>
<string name="really_remove_all_scans">Yakin menghapus semua pemindaian?</string>
<string name="clear_history">Hapus riwayat</string>
@@ -40,17 +42,19 @@
<string name="file_name">Nama berkas</string>
<string name="error_saving_binary_data">Tidak bisa menyimpan berkas</string>
<string name="error_file_exists">Berkas sudah ada</string>
<string name="connect_to_wifi">Connect to WiFi</string>
<string name="wifi_config_failed">Could not configure WiFi</string>
<string name="wifi_added">WiFi added</string>
<string name="sms_send">Send SMS</string>
<string name="sms_error">Could not send SMS</string>
<string name="tel_dial">Dial number</string>
<string name="tel_error">Could not dial number</string>
<string name="mail_send">Send mail</string>
<string name="mail_error">Could not send mail</string>
<string name="vcard_add">Add to contacts</string>
<string name="vcard_failed">Could not add to contacts</string>
<string name="vevent_add">Add to calendar</string>
<string name="vevent_failed">Could not add to calendar</string>
<string name="connect_to_wifi">Sambungkan ke WiFi</string>
<string name="wifi_config_failed">Tidak bisa mengelola WiFi</string>
<string name="wifi_added">WiFi ditambahkan</string>
<string name="sms_send">Kirim SMS</string>
<string name="sms_error">Tidak bisa mengirim SMS</string>
<string name="tel_dial">Panggil nomor</string>
<string name="tel_error">Tidak bisa memanggil nomor</string>
<string name="mail_send">Kirim surel</string>
<string name="mail_error">Tidak bisa mengirim surel</string>
<string name="vcard_add">Tambahkan ke kontak</string>
<string name="vcard_failed">Tidak bisa menambahkan ke kontak</string>
<string name="vevent_add">Tambahkan ke kalender</string>
<string name="vevent_failed">Tidak bisa menambahkan ke kalender</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
+4
View File
@@ -28,7 +28,9 @@
<string name="info">Info</string>
<string name="switch_camera">Cambia camera</string>
<string name="history">Cronologia</string>
<string name="preferences">Preferences</string>
<string name="use_history">Salva cronologia delle scansioni</string>
<string name="open_with_url">Open unknown data with URL</string>
<string name="really_remove_scan">Vuoi veramente rimuovere la scansione?</string>
<string name="really_remove_all_scans">Vuoi veramente rimuovere tutte le scansioni?</string>
<string name="clear_history">Pulisci cronologia</string>
@@ -53,4 +55,6 @@
<string name="vcard_failed">Could not add to contacts</string>
<string name="vevent_add">Add to calendar</string>
<string name="vevent_failed">Could not add to calendar</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
+4
View File
@@ -28,7 +28,9 @@
<string name="info">Informatie</string>
<string name="switch_camera">Camera wisselen</string>
<string name="history">History</string>
<string name="preferences">Preferences</string>
<string name="use_history">Save scan history</string>
<string name="open_with_url">Open unknown data with URL</string>
<string name="really_remove_scan">Really remove scan?</string>
<string name="really_remove_all_scans">Really remove all scans?</string>
<string name="clear_history">Clear history</string>
@@ -53,4 +55,6 @@
<string name="vcard_failed">Could not add to contacts</string>
<string name="vevent_add">Add to calendar</string>
<string name="vevent_failed">Could not add to calendar</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
@@ -0,0 +1,60 @@
<resources>
<string name="no_camera_no_fun">Esse aplicativo não faz sentido de uso sem acesso para a câmera. Adeus.</string>
<string name="camera_error">Sem acesso a câmera, por favor tente novamente</string>
<string name="scan_code">Escaneie o código de barras</string>
<string name="compose_barcode">Compor código de barras</string>
<string name="decode_barcode">Decodificar código de barras</string>
<string name="content">Conteúdo</string>
<string name="binary_data">(binários)</string>
<plurals name="barcode_info">
<item quantity="one">%1$s\n%2$d cacractere</item>
<item quantity="other">%1$s\n%2$d caracteres</item>
</plurals>
<string name="toggle_flash">Ativar lanterna</string>
<string name="share">Compartilhar</string>
<string name="copy_to_clipboard">Copiar para área de transferência</string>
<string name="put_into_clipboard">Colocar na área de transferência</string>
<string name="open_url">Abrir url</string>
<string name="cannot_resolve_action">Nenhuma aplicativo pode abrir isso</string>
<string name="pick_search_engine">Escolha um mecanismo de busca</string>
<string name="format">Formatar</string>
<string name="size">Tamanho em pixels</string>
<string name="width_by_height">%1$d×%2$d</string>
<string name="input_content_here">Insira o conteúdo aqui</string>
<string name="encode">CODIFICAR</string>
<string name="error_no_content">Conteúdo não disponível</string>
<string name="error_encoding_barcode">Não foi possível gerar o código de barras</string>
<string name="view_barcode">Ver código de barras</string>
<string name="info">Informações</string>
<string name="switch_camera">Trocar câmera</string>
<string name="history">Histórico</string>
<string name="preferences">Preferências</string>
<string name="use_history">Salvar histórico de escaneamento</string>
<string name="open_with_url">Abrir dados desconhecidos com URL</string>
<string name="really_remove_scan">Realmente deseja remover o escaneamento?</string>
<string name="really_remove_all_scans">Realmente deseja remover todos escaneamentos?</string>
<string name="clear_history">Limpar histórico</string>
<string name="no_barcode_found">Código de barras não encontrado</string>
<string name="pick_list_separator">Como separar itens da lista?</string>
<string name="separator_line_break">Quebra de linha</string>
<string name="separator_ruler">Régua</string>
<string name="save_as_file_name">Salvar como arquivo de imagem?</string>
<string name="file_name">Nome do arquivo</string>
<string name="error_saving_binary_data">Arquivo não pode ser salvo</string>
<string name="error_file_exists">Arquivo já existe</string>
<string name="connect_to_wifi">Conectar para o WiFi</string>
<string name="wifi_config_failed">Não foi possível configurar o WiFi</string>
<string name="wifi_added">WiFi adicionado</string>
<string name="sms_send">Enviar SMS</string>
<string name="sms_error">Não foi possível enviar o SMS</string>
<string name="tel_dial">Discar número</string>
<string name="tel_error">Não foi possível discar o número</string>
<string name="mail_send">Enviar e-mail</string>
<string name="mail_error">Não foi possível enviar o e-mail</string>
<string name="vcard_add">Adicionar para os contatos</string>
<string name="vcard_failed">NNão foi possível adicionar para os contatos</string>
<string name="vevent_add">Adicionar ao calendário</string>
<string name="vevent_failed">Não foi possível adicionar ao calendário</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
@@ -0,0 +1,60 @@
<resources>
<string name="no_camera_no_fun">没有相机权限,这个软件有啥意义。再见!</string>
<string name="camera_error">无法访问相机,请重试。</string>
<string name="scan_code">Scan code</string>
<string name="compose_barcode">制作条形码</string>
<string name="decode_barcode">解码条形码</string>
<string name="content">内容</string>
<string name="binary_data">(二进制数据)</string>
<plurals name="barcode_info">
<item quantity="one">%1$s\n%2$d 字符</item>
<item quantity="other">%1$s\n%2$d 字符</item>
</plurals>
<string name="toggle_flash">切换闪光灯</string>
<string name="share">分享</string>
<string name="copy_to_clipboard">复制到剪切板</string>
<string name="put_into_clipboard">复制到剪切板</string>
<string name="open_url">打开链接</string>
<string name="cannot_resolve_action">没有应用程序可以打开它</string>
<string name="pick_search_engine">选择一个搜索引擎</string>
<string name="format">编码格式</string>
<string name="size">图片尺寸</string>
<string name="width_by_height">%1$d×%2$d</string>
<string name="input_content_here">在这里输入内容</string>
<string name="encode">编码</string>
<string name="error_no_content">缺少内容</string>
<string name="error_encoding_barcode">无法生成条形码</string>
<string name="view_barcode">查看条形码</string>
<string name="info">信息</string>
<string name="switch_camera">切换摄像头</string>
<string name="history">历史</string>
<string name="preferences">首选项</string>
<string name="use_history">保存扫描历史</string>
<string name="open_with_url">使用URL打开未知数据</string>
<string name="really_remove_scan">确定删除记录?</string>
<string name="really_remove_all_scans">确定删除全部记录?</string>
<string name="clear_history">删除记录</string>
<string name="no_barcode_found">未找到条形码</string>
<string name="pick_list_separator">如何分隔列表项?</string>
<string name="separator_line_break"></string>
<string name="separator_ruler">分割线</string>
<string name="save_as_file_name">保存为文件?</string>
<string name="file_name">文件名</string>
<string name="error_saving_binary_data">无法保存文件</string>
<string name="error_file_exists">文件已存在</string>
<string name="connect_to_wifi">连接到WiFi</string>
<string name="wifi_config_failed">无法配置WiFi</string>
<string name="wifi_added">WiFi已添加</string>
<string name="sms_send">发送短信</string>
<string name="sms_error">无法发送短信</string>
<string name="tel_dial">拨打号码</string>
<string name="tel_error">无法拨打此号码</string>
<string name="mail_send">发送邮件</string>
<string name="mail_error">无法发送邮件</string>
<string name="vcard_add">添加到通讯录</string>
<string name="vcard_failed">无法添加到通讯录</string>
<string name="vevent_add">添加到日历</string>
<string name="vevent_failed">无法添加到日历</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
+60
View File
@@ -0,0 +1,60 @@
<resources>
<string name="no_camera_no_fun">沒有相機權限的話,這個程式根本什麽都做不了。再見!</string>
<string name="camera_error">不能開啓相機,請重試</string>
<string name="scan_code">掃描條碼</string>
<string name="compose_barcode">製作條碼</string>
<string name="decode_barcode">解讀條碼</string>
<string name="content">内容</string>
<string name="binary_data">(2進制碼)</string>
<plurals name="barcode_info">
<item quantity="one">%1$s\n%2$d 個字符</item>
<item quantity="other">%1$s\n%2$d 個字符</item>
</plurals>
<string name="toggle_flash">閃光燈</string>
<string name="share">分享</string>
<string name="copy_to_clipboard">複製</string>
<string name="put_into_clipboard">複製</string>
<string name="open_url">開啓</string>
<string name="cannot_resolve_action">無應用程式可以開啓</string>
<string name="pick_search_engine">選擇搜尋引擎</string>
<string name="format">格式</string>
<string name="size">大小(pixels)</string>
<string name="width_by_height">%1$d×%2$d</string>
<string name="input_content_here">在此輸入</string>
<string name="encode">製作條碼</string>
<string name="error_no_content">找不到内容</string>
<string name="error_encoding_barcode">條碼製作失敗</string>
<string name="view_barcode">檢視條碼</string>
<string name="info">資訊</string>
<string name="switch_camera">切換相機</string>
<string name="history">歷史</string>
<string name="use_history">儲存掃描歷史</string>
<string name="really_remove_scan">真的要移除掃描記錄?</string>
<string name="really_remove_all_scans">真的要移除所有掃描記錄?</string>
<string name="clear_history">清除記錄</string>
<string name="no_barcode_found">找不到條碼</string>
<string name="pick_list_separator">如何分開列表項目?</string>
<string name="separator_line_break">Line break</string>
<string name="separator_ruler">直尺</string>
<string name="save_as_file_name">儲存成檔案?</string>
<string name="file_name">檔案名稱</string>
<string name="error_saving_binary_data">不能儲存檔案</string>
<string name="error_file_exists">檔案已存在</string>
<string name="connect_to_wifi">連接至 WiFi</string>
<string name="wifi_config_failed">WiFi連接設定失敗</string>
<string name="wifi_added">成功添加WiFi</string>
<string name="sms_send">傳送SMS</string>
<string name="sms_error">不能傳送SMS</string>
<string name="tel_dial">撥號</string>
<string name="tel_error">不能撥號</string>
<string name="mail_send">發送電郵</string>
<string name="mail_error">不能發送電郵</string>
<string name="vcard_add">添加至聯絡人</string>
<string name="vcard_failed">不能添加至聯絡人</string>
<string name="vevent_add">添加至行事曆</string>
<string name="vevent_failed">不能添加至行事曆</string>
<string name="preferences">Preferences</string>
<string name="open_with_url">Preferences</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
@@ -1,3 +1,4 @@
<resources>
<string name="app_name">Binary Eye</string>
<string name="open_with_url_hint">http://example.com?data=</string>
</resources>
+4
View File
@@ -28,7 +28,9 @@
<string name="info">Info</string>
<string name="switch_camera">Switch camera</string>
<string name="history">History</string>
<string name="preferences">Preferences</string>
<string name="use_history">Save scan history</string>
<string name="open_with_url">Open unknown data with URL</string>
<string name="really_remove_scan">Really remove scan?</string>
<string name="really_remove_all_scans">Really remove all scans?</string>
<string name="clear_history">Clear history</string>
@@ -53,4 +55,6 @@
<string name="vcard_failed">Could not add to contacts</string>
<string name="vevent_add">Add to calendar</string>
<string name="vevent_failed">Could not add to calendar</string>
<string name="otpauth_add">Add 2FA</string>
<string name="otpauth_error">Could not add 2FA</string>
</resources>
@@ -0,0 +1,19 @@
package de.markusfisch.android.binaryeye
import junit.framework.TestCase.fail
fun simpleFail(message: String = "Unknown reason, but failed"): Nothing {
fail(message)
throw IllegalStateException("You should never have reached this point in the code, but anyways: $message")
}
inline fun <reified E : Throwable> assertThrows(message: String = "Unknown reason, but didn't failed even though should fail", block: () -> Unit) {
try {
block()
fail(message)
} catch (e: Throwable) {
if (e !is E) {
fail("Got unexpected other Throwable: ${e::class.java.simpleName}\n$e")
}
}
}
@@ -0,0 +1,139 @@
package de.markusfisch.android.binaryeye.actions.otpauth
import de.markusfisch.android.binaryeye.assertThrows
import de.markusfisch.android.binaryeye.simpleFail
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertNull
import org.junit.Test
class OtpauthParserTest {
@Test
fun noOtpauthUri() {
assertNull(OtpauthParser("random string"))
}
@Test
fun missingSecret() {
assertNull(OtpauthParser("otpauth://totp/issuerName:accountName"))
}
@Test
fun missingCounterHotp() {
assertNull(OtpauthParser("otpauth://hotp/accountName?secret=secretString"))
}
@Test
fun minimalHotp() {
val parser = validParser("otpauth://hotp/accountName?secret=secretString&counter=50")
assertEquals("hotp", parser.otpType)
assertEquals("accountName", parser.accountName)
assertEquals("secretString", parser.secret)
assertEquals("SHA1", parser.algorithm)
assertEquals(6, parser.digits)
assertEquals(30, parser.period)
assertEquals(50, parser.counter)
}
@Test
fun normalHotp() {
val parser = validParser("otpauth://hotp/issuerName:accountName?secret=secretString&counter=0")
assertEquals("hotp", parser.otpType)
assertEquals("issuerName", parser.issuer)
assertEquals("accountName", parser.accountName)
assertEquals("secretString", parser.secret)
assertEquals("SHA1", parser.algorithm)
assertEquals(6, parser.digits)
assertEquals(30, parser.period)
assertEquals(0, parser.counter)
}
@Test
fun missingIssuerParamHotp() {
val parser = validParser("otpauth://hotp/issuerName:accountName?secret=secretString&counter=50&algorithm=SHA256&digits=8")
assertEquals("hotp", parser.otpType)
assertEquals("issuerName", parser.issuer)
assertEquals("accountName", parser.accountName)
assertEquals("secretString", parser.secret)
assertEquals("SHA256", parser.algorithm)
assertEquals(8, parser.digits)
assertEquals(30, parser.period)
assertEquals(50, parser.counter)
}
@Test
fun fullHotp() {
val parser = validParser("otpauth://hotp/issuerName:accountName?secret=secretString&counter=50&issuer=issuerName&algorithm=SHA256&digits=8")
assertEquals("hotp", parser.otpType)
assertEquals("issuerName", parser.issuer)
assertEquals("accountName", parser.accountName)
assertEquals("secretString", parser.secret)
assertEquals("SHA256", parser.algorithm)
assertEquals(8, parser.digits)
assertEquals(30, parser.period)
assertEquals(50, parser.counter)
}
@Test
fun minimalTotp() {
val parser = validParser("otpauth://totp/accountName?secret=secretString")
assertEquals("totp", parser.otpType)
assertEquals("accountName", parser.accountName)
assertEquals("secretString", parser.secret)
assertEquals("SHA1", parser.algorithm)
assertEquals(6, parser.digits)
assertEquals(30, parser.period)
assertThrows<NumberFormatException> {
parser.counter
}
}
@Test
fun normalTotp() {
val parser = validParser("otpauth://totp/issuerName:accountName?secret=secretString")
assertEquals("totp", parser.otpType)
assertEquals("issuerName", parser.issuer)
assertEquals("accountName", parser.accountName)
assertEquals("secretString", parser.secret)
assertEquals("SHA1", parser.algorithm)
assertEquals(6, parser.digits)
assertEquals(30, parser.period)
assertThrows<NumberFormatException> {
parser.counter
}
}
@Test
fun missingIssuerParamTotp() {
val parser = validParser("otpauth://totp/issuerName:accountName?secret=secretString&algorithm=SHA256&digits=8&period=60")
assertEquals("totp", parser.otpType)
assertEquals("issuerName", parser.issuer)
assertEquals("accountName", parser.accountName)
assertEquals("secretString", parser.secret)
assertEquals("SHA256", parser.algorithm)
assertEquals(8, parser.digits)
assertEquals(60, parser.period)
assertThrows<NumberFormatException> {
parser.counter
}
}
@Test
fun fullTotp() {
val parser = validParser("otpauth://totp/issuerName:accountName?secret=secretString&issuer=issuerName&algorithm=SHA256&digits=8&period=60")
assertEquals("totp", parser.otpType)
assertEquals("issuerName", parser.issuer)
assertEquals("accountName", parser.accountName)
assertEquals("secretString", parser.secret)
assertEquals("SHA256", parser.algorithm)
assertEquals(8, parser.digits)
assertEquals(60, parser.period)
assertThrows<NumberFormatException> {
parser.counter
}
}
private fun validParser(input: String): OtpauthParser {
return OtpauthParser(input) ?: simpleFail("Could not get parser of valid input")
}
}
@@ -1,10 +1,10 @@
package de.markusfisch.android.binaryeye.actions.wifi
import de.markusfisch.android.binaryeye.simpleFail
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertNull
import junit.framework.TestCase.assertTrue
import junit.framework.TestCase.fail
import org.junit.Test
class WifiConfigurationFactoryTest {
@@ -84,11 +84,6 @@ class WifiConfigurationFactoryTest {
assertFalse(info.hidden)
}
private fun simpleFail(message: String = "Unknown reason, but failed"): Nothing {
fail(message)
throw IllegalStateException("You should never have reached this point in the code, but anyways: $message")
}
private fun simpleDataAccessor(wifiString: String): WifiConfigurationFactory.SimpleDataAccessor {
val map = WifiConfigurationFactory.parseMap(wifiString)
?: simpleFail("parsing map of valid string fails ($wifiString)")