Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67471ee141 | ||
|
|
6999f0a863 | ||
|
|
6574a5d651 | ||
|
|
1639e73738 | ||
|
|
68fa67f54f | ||
|
|
326c34b6c1 | ||
|
|
a43dca3644 | ||
|
|
168ccf7d10 | ||
|
|
a9630b4d53 | ||
|
|
4a138bd425 | ||
|
|
339ff59270 | ||
|
|
d208ec12bc | ||
|
|
893ddefa71 | ||
|
|
5d56365e79 | ||
|
|
3237467503 | ||
|
|
346529469c | ||
|
|
9f4e420dbb | ||
|
|
cf4020c613 | ||
|
|
93edde7ed1 | ||
|
|
362e462c2a | ||
|
|
a7241bc0fb | ||
|
|
f26046f34b | ||
|
|
a70813ea5c | ||
|
|
3f251fdb66 | ||
|
|
b76cf329dd | ||
|
|
e0ad177a62 | ||
|
|
1223bd3679 | ||
|
|
b4e24fa328 |
@@ -1,5 +1,26 @@
|
||||
# Change Log
|
||||
|
||||
# 1.22.3
|
||||
* Fix broken RenderScript built
|
||||
|
||||
# 1.22.2
|
||||
* Fix getting window insets for Android Lollipop and above
|
||||
|
||||
# 1.22.1
|
||||
* Ensure non-printable content is saved as raw data
|
||||
|
||||
# 1.22.0
|
||||
* Highlight detected barcodes in camera view
|
||||
* Add bing and yandex search engines
|
||||
* Update Chinese Translation
|
||||
* Update Italian translation
|
||||
* Update Indonesian translation
|
||||
|
||||
# 1.21.0
|
||||
* Save and restore history list state
|
||||
* Improve scanning from large images
|
||||
* Fix opening image files by "Open with"
|
||||
|
||||
# 1.20.1
|
||||
* Fix window insets below Android Lollipop
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ to squash when merging into master:
|
||||
|
||||
$ git merge cool_feature --squash
|
||||
|
||||
Then write a [good commit messages][commit_messages] to keep the history
|
||||
Then write a [good commit message][commit_messages] to keep the history
|
||||
meaningful and useful. One feature, one commit.
|
||||
|
||||
[android_best_practices]: https://developer.android.com/distribute/best-practices/develop/
|
||||
|
||||
@@ -2,23 +2,51 @@
|
||||
|
||||
Yet another barcode scanner for Android. As if there weren't [enough][play].
|
||||
|
||||
This one is free, without any ads and completely open source.
|
||||
This one is free, without any ads and open source.
|
||||
|
||||
Works in portrait and landscape orientation, can read inverted codes,
|
||||
comes in Material Design and can also generate barcodes.
|
||||
|
||||
Uses the [ZXing][zxing] ("Zebra Crossing") barcode scanning library that
|
||||
supports the following barcode formats for reading:
|
||||
AZTEC, CODABAR, CODE 39, CODE 93, CODE 128, DATA MATRIX, EAN 8, EAN 13, ITF,
|
||||
MAXICODE, PDF417, QR CODE, RSS 14, RSS EXPANDED, UPC A, UPC E and
|
||||
UPC EAN EXTENSION.
|
||||
Binary Eye uses the [ZXing][zxing] ("Zebra Crossing") barcode scanning
|
||||
library.
|
||||
|
||||
And those barcodes formats can be generated with ZXing:
|
||||
AZTEC, CODABAR, CODE 39, CODE 128, DATA MATRIX, EAN 8, EAN 13, ITF, PDF 417,
|
||||
QR CODE and UPC A.
|
||||
## Supported Barcode Formats
|
||||
|
||||
And it's written in [Kotlin][kotlin] because I wanted to explore that a
|
||||
bit more.
|
||||
### Read
|
||||
|
||||
ZXing can _read_ the following barcode formats:
|
||||
* [AZTEC][aztec]
|
||||
* [CODABAR][codabar]
|
||||
* [CODE 39][code_39]
|
||||
* [CODE 93][code_93]
|
||||
* [CODE 128][code_128]
|
||||
* [DATA MATRIX][data_matrix]
|
||||
* [EAN 8][ean_8]
|
||||
* [EAN 13][ean_13]
|
||||
* [ITF][itf]
|
||||
* [MAXICODE][maxicode]
|
||||
* [PDF417][pdf417]
|
||||
* [QR CODE][qr_code]
|
||||
* [RSS 14][rss]
|
||||
* [RSS EXPANDED][rss]
|
||||
* [UPC A][upc_a]
|
||||
* [UPC E][upc_e]
|
||||
* [UPC EAN EXTENSION][upc_ean]
|
||||
|
||||
### Generate
|
||||
|
||||
ZXing can _generate_ the following barcode formats:
|
||||
* [AZTEC][aztec]
|
||||
* [CODABAR][codabar]
|
||||
* [CODE 39][code_39]
|
||||
* [CODE 128][code_128]
|
||||
* [DATA MATRIX][data_matrix]
|
||||
* [EAN 8][ean_8]
|
||||
* [EAN 13][ean_13]
|
||||
* [ITF][itf]
|
||||
* [PDF 417][pdf417]
|
||||
* [QR CODE][qr_code]
|
||||
* [UPC A][upc_a]
|
||||
|
||||
## Screenshots
|
||||
|
||||
@@ -39,3 +67,19 @@ bit more.
|
||||
[play]: https://play.google.com/store/search?q=barcode%20scanner&c=apps
|
||||
[zxing]: https://github.com/zxing/zxing
|
||||
[kotlin]: http://kotlinlang.org/
|
||||
[aztec]: https://en.wikipedia.org/wiki/Aztec_Code
|
||||
[codabar]: https://en.wikipedia.org/wiki/Codabar
|
||||
[code_39]: https://en.wikipedia.org/wiki/Code_39
|
||||
[code_93]: https://en.wikipedia.org/wiki/Code_93
|
||||
[code_128]: https://en.wikipedia.org/wiki/Code_128
|
||||
[data_matrix]: https://en.wikipedia.org/wiki/Data_Matrix
|
||||
[ean_8]: https://en.wikipedia.org/wiki/EAN-8
|
||||
[ean_13]: https://en.wikipedia.org/wiki/International_Article_Number
|
||||
[itf]: https://en.wikipedia.org/wiki/Interleaved_2_of_5
|
||||
[maxicode]: https://en.wikipedia.org/wiki/MaxiCode
|
||||
[pdf417]: https://en.wikipedia.org/wiki/PDF417
|
||||
[qr_code]: https://en.wikipedia.org/wiki/QR_code
|
||||
[rss]: https://en.wikipedia.org/wiki/GS1_DataBar
|
||||
[upc_a]: https://en.wikipedia.org/wiki/Universal_Product_Code
|
||||
[upc_e]: https://en.wikipedia.org/wiki/Universal_Product_Code#UPC-E
|
||||
[upc_ean]: https://en.wikipedia.org/wiki/Universal_Product_Code#EAN-13
|
||||
|
||||
+4
-2
@@ -9,8 +9,8 @@ android {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion sdk_version
|
||||
|
||||
versionCode 50
|
||||
versionName '1.20.1'
|
||||
versionCode 55
|
||||
versionName '1.22.3'
|
||||
|
||||
// it's recommended to set this value to the lowest API level
|
||||
// able to provide all the functionality
|
||||
@@ -18,6 +18,8 @@ android {
|
||||
renderscriptSupportModeEnabled true
|
||||
|
||||
testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
|
||||
|
||||
buildConfigField 'boolean', 'IS_CATALINA', is_catalina.toString()
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:name=".app.BinaryEyeApp"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="true"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:supportsRtl="true"
|
||||
android:resizeableActivity="true"
|
||||
android:label="@string/app_name"
|
||||
@@ -55,7 +55,8 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.PickActivity"
|
||||
android:label="@string/pick_code_to_scan">
|
||||
android:label="@string/pick_code_to_scan"
|
||||
tools:ignore="AppLinkUrlError">
|
||||
<intent-filter android:label="@string/decode_barcode">
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
@@ -64,7 +65,7 @@
|
||||
<intent-filter android:label="@string/decode_barcode">
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="image/*" android:scheme="file"/>
|
||||
<data android:mimeType="image/*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
|
||||
@@ -22,7 +22,10 @@ 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.graphics.Mapping
|
||||
import de.markusfisch.android.binaryeye.graphics.frameToView
|
||||
import de.markusfisch.android.binaryeye.rs.Preprocessor
|
||||
import de.markusfisch.android.binaryeye.widget.DetectorView
|
||||
import de.markusfisch.android.binaryeye.zxing.Zxing
|
||||
import de.markusfisch.android.cameraview.widget.CameraView
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@@ -33,6 +36,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var vibrator: Vibrator
|
||||
private lateinit var cameraView: CameraView
|
||||
private lateinit var detectorView: DetectorView
|
||||
private lateinit var zoomBar: SeekBar
|
||||
private lateinit var flashFab: View
|
||||
|
||||
@@ -83,12 +87,13 @@ class CameraActivity : AppCompatActivity() {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_camera)
|
||||
|
||||
vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
|
||||
initSystemBars(this)
|
||||
setSupportActionBar(findViewById(R.id.toolbar) as Toolbar)
|
||||
|
||||
vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
|
||||
cameraView = findViewById(R.id.camera_view) as CameraView
|
||||
detectorView = findViewById(R.id.detector_view) as DetectorView
|
||||
zoomBar = findViewById(R.id.zoom) as SeekBar
|
||||
flashFab = findViewById(R.id.flash)
|
||||
flashFab.setOnClickListener { toggleTorchMode() }
|
||||
@@ -264,6 +269,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
val frameWidth = cameraView.frameWidth
|
||||
val frameHeight = cameraView.frameHeight
|
||||
val frameOrientation = cameraView.frameOrientation
|
||||
var mapping: Mapping? = null
|
||||
var decoding = true
|
||||
camera.setPreviewCallback { frameData, _ ->
|
||||
if (decoding) {
|
||||
@@ -274,7 +280,19 @@ class CameraActivity : AppCompatActivity() {
|
||||
frameOrientation
|
||||
)
|
||||
result?.let {
|
||||
preprocessor?.let {
|
||||
mapping = mapping ?: frameToView(
|
||||
it.outWidth,
|
||||
it.outHeight,
|
||||
cameraView.previewRect
|
||||
)
|
||||
}
|
||||
cameraView.post {
|
||||
mapping?.let {
|
||||
detectorView.mark(
|
||||
it.map(result.resultPoints)
|
||||
)
|
||||
}
|
||||
vibrator.vibrate(100)
|
||||
showResult(
|
||||
this@CameraActivity,
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.provider.MediaStore
|
||||
import android.os.Vibrator
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.Menu
|
||||
@@ -19,22 +21,23 @@ import de.markusfisch.android.binaryeye.app.initSystemBars
|
||||
import de.markusfisch.android.binaryeye.app.setWindowInsetListener
|
||||
import de.markusfisch.android.binaryeye.app.setupInsets
|
||||
import de.markusfisch.android.binaryeye.graphics.crop
|
||||
import de.markusfisch.android.binaryeye.graphics.downsizeIfBigger
|
||||
import de.markusfisch.android.binaryeye.graphics.loadImageUri
|
||||
import de.markusfisch.android.binaryeye.graphics.mapResult
|
||||
import de.markusfisch.android.binaryeye.widget.CropImageView
|
||||
import de.markusfisch.android.binaryeye.zxing.Zxing
|
||||
import java.io.IOException
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class PickActivity : AppCompatActivity() {
|
||||
private val zxing = Zxing()
|
||||
|
||||
private lateinit var vibrator: Vibrator
|
||||
private lateinit var cropImageView: CropImageView
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_pick)
|
||||
|
||||
vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
|
||||
initSystemBars(this)
|
||||
val toolbar = findViewById(R.id.toolbar) as Toolbar
|
||||
setupInsets(findViewById(android.R.id.content), toolbar)
|
||||
@@ -69,7 +72,7 @@ class PickActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
val scannedRect = Rect()
|
||||
val scanBounds: () -> Result? = {
|
||||
val scanWithinBounds: () -> Result? = {
|
||||
var result: Result? = null
|
||||
crop(
|
||||
bitmap,
|
||||
@@ -85,38 +88,24 @@ class PickActivity : AppCompatActivity() {
|
||||
cropImageView = findViewById(R.id.image) as CropImageView
|
||||
cropImageView.setImageBitmap(bitmap)
|
||||
cropImageView.onScan = {
|
||||
val rect = Rect()
|
||||
scanBounds()?.also {
|
||||
rect.left = Int.MAX_VALUE
|
||||
rect.top = Int.MAX_VALUE
|
||||
for (rp in it.resultPoints) {
|
||||
val x = rp.x.toInt()
|
||||
val y = rp.y.toInt()
|
||||
rect.left = min(rect.left, x)
|
||||
rect.right = max(rect.right, x)
|
||||
rect.top = min(rect.top, y)
|
||||
rect.bottom = max(rect.bottom, y)
|
||||
}
|
||||
// map result points onto view
|
||||
val bounds = cropImageView.getBoundsRect()
|
||||
val fx = bounds.width() / scannedRect.width().toFloat()
|
||||
val fy = bounds.height() / scannedRect.height().toFloat()
|
||||
rect.set(
|
||||
(rect.left * fx).toInt(),
|
||||
(rect.top * fy).toInt(),
|
||||
(rect.right * fx).toInt(),
|
||||
(rect.bottom * fx).toInt()
|
||||
var points: List<Point>? = null
|
||||
scanWithinBounds()?.let {
|
||||
points = mapResult(
|
||||
scannedRect.width(),
|
||||
scannedRect.height(),
|
||||
cropImageView.getBoundsRect(),
|
||||
it
|
||||
)
|
||||
rect.offset(bounds.left.toInt(), bounds.top.toInt())
|
||||
vibrator.vibrate(100)
|
||||
}
|
||||
rect
|
||||
points
|
||||
}
|
||||
setWindowInsetListener { insets ->
|
||||
cropImageView.windowInsets.set(insets)
|
||||
}
|
||||
|
||||
findViewById(R.id.scan).setOnClickListener {
|
||||
scanImage(scanBounds())
|
||||
scanImage(scanWithinBounds())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,21 +132,12 @@ class PickActivity : AppCompatActivity() {
|
||||
val uri = intent.getParcelableExtra<Parcelable>(
|
||||
Intent.EXTRA_STREAM
|
||||
) as? Uri ?: return null
|
||||
return loadImageUri(uri)
|
||||
return loadImageUri(contentResolver, uri)
|
||||
}
|
||||
|
||||
private fun loadImageToOpen(intent: Intent): Bitmap? {
|
||||
val uri = intent.data ?: return null
|
||||
return loadImageUri(uri)
|
||||
}
|
||||
|
||||
private fun loadImageUri(uri: Uri): Bitmap? = try {
|
||||
downsizeIfBigger(
|
||||
MediaStore.Images.Media.getBitmap(contentResolver, uri),
|
||||
1024
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
return loadImageUri(contentResolver, uri)
|
||||
}
|
||||
|
||||
private fun scanImage(result: Result?) {
|
||||
|
||||
@@ -20,11 +20,9 @@ class ScansAdapter(context: Context, cursor: Cursor) :
|
||||
context: Context,
|
||||
cursor: Cursor,
|
||||
parent: ViewGroup
|
||||
): View {
|
||||
return LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.row_scan, parent, false
|
||||
)
|
||||
}
|
||||
) = LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.row_scan, parent, false
|
||||
)
|
||||
|
||||
override fun bindView(
|
||||
view: View,
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import android.app.Application
|
||||
import android.support.v8.renderscript.RenderScript
|
||||
import de.markusfisch.android.binaryeye.BuildConfig
|
||||
import de.markusfisch.android.binaryeye.preference.Preferences
|
||||
import de.markusfisch.android.binaryeye.repository.DatabaseRepository
|
||||
|
||||
@@ -12,9 +13,19 @@ class BinaryEyeApp : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
// required to make RenderScript work for Lineage 16.0
|
||||
// possibly because of a system/device bug
|
||||
RenderScript.forceCompat()
|
||||
// Since RenderScript can no longer be compiled on macOS Catalina
|
||||
// because Catalina cannot run 32bit binaries and Google failed
|
||||
// to provide a 64bit compiler in time. Now, as if that wasn't
|
||||
// bad enough, `RenderScript.forceCompat()` makes any build compiled
|
||||
// with the new build tools that provide a 64bit compiler crash
|
||||
// so we need to exclude this if we're building on Catalina.
|
||||
// Maybe `RenderScript.forceCompat()` isn't required anymore for
|
||||
// those new builds but I don't have a device to test this.
|
||||
if (!BuildConfig.IS_CATALINA) {
|
||||
// required to make RenderScript work for Lineage 16.0
|
||||
// possibly because of a system/device bug
|
||||
RenderScript.forceCompat()
|
||||
}
|
||||
|
||||
db.open(this)
|
||||
prefs.init(this)
|
||||
|
||||
@@ -82,8 +82,9 @@ private fun getAppCompatActivity(context: Context): AppCompatActivity? {
|
||||
}
|
||||
|
||||
private var windowInsetsListener: ((insets: Rect) -> Unit)? = null
|
||||
// invoke this from Fragment.onCreateView() *or* Activity.onCreate()
|
||||
fun setWindowInsetListener(listener: (insets: Rect) -> Unit) {
|
||||
if (windowInsets.top > 0) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
listener(windowInsets)
|
||||
} else {
|
||||
windowInsetsListener = listener
|
||||
@@ -91,14 +92,18 @@ fun setWindowInsetListener(listener: (insets: Rect) -> Unit) {
|
||||
}
|
||||
|
||||
private val windowInsets = Rect()
|
||||
// invoke this from Activity.onCreate() to setup listening for insets
|
||||
fun setupInsets(view: View, toolbar: Toolbar) {
|
||||
val toolBarHeight = toolbar.layoutParams.height
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
// save insets so setWindowInsetListener() can return them
|
||||
// when it's called from Fragment.onCreateView() later on
|
||||
windowInsets.set(0, toolBarHeight, 0, 0)
|
||||
windowInsetsListener?.also { it(windowInsets) }
|
||||
return
|
||||
}
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->
|
||||
// runs *after* layout and thus *after* Fragment.onCreateView()
|
||||
if (insets.hasSystemWindowInsets()) {
|
||||
windowInsets.set(
|
||||
insets.systemWindowInsetLeft,
|
||||
|
||||
@@ -59,9 +59,9 @@ class Database {
|
||||
timestamp
|
||||
).toString()
|
||||
)
|
||||
if (hasNonPrintableCharacters(content) && raw != null) {
|
||||
if (hasNonPrintableCharacters(content)) {
|
||||
cv.put(SCANS_CONTENT, "")
|
||||
cv.put(SCANS_RAW, raw)
|
||||
cv.put(SCANS_RAW, if (raw != null) raw else content.toByteArray())
|
||||
} else {
|
||||
cv.put(SCANS_CONTENT, content)
|
||||
}
|
||||
|
||||
@@ -3,12 +3,7 @@ package de.markusfisch.android.binaryeye.fragment
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
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.view.inputmethod.InputMethodManager
|
||||
import android.widget.*
|
||||
import com.google.zxing.BarcodeFormat
|
||||
|
||||
@@ -3,6 +3,7 @@ package de.markusfisch.android.binaryeye.fragment
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.support.annotation.WorkerThread
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.widget.SwitchCompat
|
||||
@@ -27,10 +28,12 @@ class HistoryFragment : Fragment() {
|
||||
private lateinit var fab: View
|
||||
private lateinit var progressView: View
|
||||
|
||||
private var scansAdapter: ScansAdapter? = null
|
||||
private val parentJob = Job()
|
||||
private val scope = CoroutineScope(Dispatchers.IO + parentJob)
|
||||
|
||||
private var scansAdapter: ScansAdapter? = null
|
||||
private var listViewState: Parcelable? = null
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
@@ -96,6 +99,11 @@ class HistoryFragment : Fragment() {
|
||||
update(context)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
listViewState = listView.onSaveInstanceState()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.fragment_history, menu)
|
||||
}
|
||||
@@ -137,6 +145,9 @@ class HistoryFragment : Fragment() {
|
||||
scansAdapter?.also { it.changeCursor(null) }
|
||||
scansAdapter = ScansAdapter(context, it)
|
||||
listView.adapter = scansAdapter
|
||||
listViewState?.also {
|
||||
listView.onRestoreInstanceState(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,52 @@
|
||||
package de.markusfisch.android.binaryeye.graphics
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.RectF
|
||||
import kotlin.math.max
|
||||
import android.net.Uri
|
||||
import java.io.IOException
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun downsizeIfBigger(bitmap: Bitmap, maxSize: Int): Bitmap = if (
|
||||
max(bitmap.width, bitmap.height) > maxSize
|
||||
) {
|
||||
val srcWidth = bitmap.width
|
||||
val srcHeight = bitmap.height
|
||||
var newWidth = maxSize
|
||||
var newHeight = maxSize
|
||||
if (srcWidth > srcHeight) {
|
||||
newHeight = (newWidth.toFloat() / srcWidth.toFloat() *
|
||||
srcHeight.toFloat()).roundToInt()
|
||||
} else {
|
||||
newWidth = (newHeight.toFloat() / srcHeight.toFloat() *
|
||||
srcWidth.toFloat()).roundToInt()
|
||||
fun loadImageUri(cr: ContentResolver, uri: Uri): Bitmap? = try {
|
||||
val options = BitmapFactory.Options()
|
||||
cr.openInputStream(uri)?.use {
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeStream(it, null, options)
|
||||
options.inSampleSize = calculateInSampleSize(
|
||||
options.outWidth,
|
||||
options.outHeight,
|
||||
1024,
|
||||
1024
|
||||
)
|
||||
options.inJustDecodeBounds = false
|
||||
}
|
||||
Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true)
|
||||
} else {
|
||||
bitmap
|
||||
cr.openInputStream(uri)?.use {
|
||||
BitmapFactory.decodeStream(it, null, options)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun calculateInSampleSize(
|
||||
width: Int,
|
||||
height: Int,
|
||||
reqWidth: Int,
|
||||
reqHeight: Int
|
||||
): Int {
|
||||
var inSampleSize = 1
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
val halfHeight = height / 2
|
||||
val halfWidth = width / 2
|
||||
while (
|
||||
halfHeight / inSampleSize >= reqHeight ||
|
||||
halfWidth / inSampleSize >= reqWidth
|
||||
) {
|
||||
inSampleSize *= 2
|
||||
}
|
||||
}
|
||||
return inSampleSize
|
||||
}
|
||||
|
||||
fun crop(bitmap: Bitmap, rect: RectF, rotation: Float) = try {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package de.markusfisch.android.binaryeye.graphics
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.support.v4.content.ContextCompat
|
||||
import com.google.zxing.Result
|
||||
import com.google.zxing.ResultPoint
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class Candidates(context: Context) {
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val radius = 8f * context.resources.displayMetrics.density
|
||||
|
||||
init {
|
||||
paint.color = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.candidate
|
||||
)
|
||||
paint.style = Paint.Style.FILL
|
||||
}
|
||||
|
||||
fun draw(canvas: Canvas, points: List<Point>) {
|
||||
for (point in points) {
|
||||
canvas.drawCircle(
|
||||
point.x.toFloat(),
|
||||
point.y.toFloat(),
|
||||
radius,
|
||||
paint
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun mapResult(
|
||||
width: Int,
|
||||
height: Int,
|
||||
viewRect: Rect,
|
||||
result: Result
|
||||
): List<Point> = frameToView(width, height, viewRect).map(result.resultPoints)
|
||||
|
||||
fun frameToView(width: Int, height: Int, viewRect: Rect) = Mapping(
|
||||
viewRect.width().toFloat() / width.toFloat(),
|
||||
viewRect.height().toFloat() / height.toFloat(),
|
||||
viewRect.left,
|
||||
viewRect.top
|
||||
)
|
||||
|
||||
data class Mapping(
|
||||
val ratioX: Float,
|
||||
val ratioY: Float,
|
||||
val offsetX: Int,
|
||||
val offsetY: Int
|
||||
) {
|
||||
fun map(points: Array<ResultPoint>): List<Point> {
|
||||
return points.map {
|
||||
Point(
|
||||
(it.x * ratioX).roundToInt() + offsetX,
|
||||
(it.y * ratioY).roundToInt() + offsetY
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,36 +5,34 @@ import android.graphics.*
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.AttributeSet
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.graphics.Candidates
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class CropImageView(context: Context, attr: AttributeSet) :
|
||||
ConfinedScalingImageView(context, attr) {
|
||||
val windowInsets = Rect()
|
||||
|
||||
var onScan: (() -> Rect)? = null
|
||||
var onScan: (() -> List<Point>?)? = null
|
||||
|
||||
private val candidates = Candidates(context)
|
||||
private val boundsPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val candidatePaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val lastMappedRect = RectF()
|
||||
private val dp = context.resources.displayMetrics.density
|
||||
private val padding: Int = (dp * 24f).roundToInt()
|
||||
private val onScanRunnable = Runnable {
|
||||
onScan?.invoke()?.also {
|
||||
candidateRect = it
|
||||
candidatePoints = it
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private var candidateRect: Rect? = null
|
||||
private var candidatePoints: List<Point>? = null
|
||||
|
||||
init {
|
||||
boundsPaint.color = ContextCompat.getColor(context, R.color.crop_bound)
|
||||
boundsPaint.style = Paint.Style.STROKE
|
||||
boundsPaint.strokeWidth = dp * 2f
|
||||
boundsPaint.pathEffect = DashPathEffect(floatArrayOf(dp * 10f, dp * 10f), 0f)
|
||||
candidatePaint.color = ContextCompat.getColor(context, R.color.candidate)
|
||||
candidatePaint.style = Paint.Style.FILL_AND_STROKE
|
||||
candidatePaint.strokeWidth = dp * 3f
|
||||
scaleType = ScaleType.CENTER_CROP
|
||||
}
|
||||
|
||||
@@ -54,9 +52,12 @@ class CropImageView(context: Context, attr: AttributeSet) :
|
||||
)
|
||||
}
|
||||
|
||||
fun getBoundsRect(): RectF {
|
||||
return bounds
|
||||
}
|
||||
fun getBoundsRect() = Rect(
|
||||
bounds.left.roundToInt(),
|
||||
bounds.top.roundToInt(),
|
||||
bounds.right.roundToInt(),
|
||||
bounds.bottom.roundToInt()
|
||||
)
|
||||
|
||||
private fun setBoundsWithPadding(
|
||||
left: Int,
|
||||
@@ -84,11 +85,10 @@ class CropImageView(context: Context, attr: AttributeSet) :
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
canvas.drawRect(bounds, boundsPaint)
|
||||
val rc = candidateRect
|
||||
if (rc != null && rc.width() > 0) {
|
||||
canvas.drawRect(rc, candidatePaint)
|
||||
candidateRect = null
|
||||
candidatePoints?.let {
|
||||
candidates.draw(canvas, it)
|
||||
}
|
||||
candidatePoints = null
|
||||
val mr = mappedRect ?: return
|
||||
if (mr != lastMappedRect) {
|
||||
removeCallbacks(onScanRunnable)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.markusfisch.android.binaryeye.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Point
|
||||
import android.graphics.PorterDuff
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import de.markusfisch.android.binaryeye.graphics.Candidates
|
||||
|
||||
class DetectorView : View {
|
||||
private val candidates = Candidates(context)
|
||||
private var marks: List<Point>? = null
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) :
|
||||
super(context, attrs)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) :
|
||||
super(context, attrs, defStyleAttr)
|
||||
|
||||
fun mark(points: List<Point>) {
|
||||
marks = points
|
||||
invalidate()
|
||||
postDelayed({
|
||||
marks = null
|
||||
invalidate()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
canvas.drawColor(0, PorterDuff.Mode.CLEAR)
|
||||
marks?.let {
|
||||
candidates.draw(canvas, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import com.google.zxing.common.HybridBinarizer
|
||||
import java.util.*
|
||||
|
||||
class Zxing {
|
||||
private val multiFormatReader: MultiFormatReader = MultiFormatReader()
|
||||
private val multiFormatReader = MultiFormatReader()
|
||||
|
||||
init {
|
||||
val decodeFormats = EnumSet.noneOf<BarcodeFormat>(
|
||||
@@ -63,10 +63,11 @@ class Zxing {
|
||||
|
||||
fun decodePositiveNegative(bitmap: Bitmap): Result? {
|
||||
val result = decode(bitmap, false)
|
||||
if (result != null) {
|
||||
return result
|
||||
return if (result != null) {
|
||||
result
|
||||
} else {
|
||||
decode(bitmap, true)
|
||||
}
|
||||
return decode(bitmap, true)
|
||||
}
|
||||
|
||||
fun decode(bitmap: Bitmap, invert: Boolean = false): Result? {
|
||||
@@ -86,8 +87,10 @@ class Zxing {
|
||||
} else {
|
||||
bitmap
|
||||
}.getPixels(pixels, 0, width, 0, 0, width, height)
|
||||
val source = RGBLuminanceSource(width, height, pixels)
|
||||
return decodeLuminanceSource(source, invert)
|
||||
return decodeLuminanceSource(
|
||||
RGBLuminanceSource(width, height, pixels),
|
||||
invert
|
||||
)
|
||||
}
|
||||
|
||||
private fun decodeLuminanceSource(
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
android:id="@+id/camera_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<de.markusfisch.android.binaryeye.widget.DetectorView
|
||||
android:id="@+id/detector_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<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>
|
||||
<string name="binary_data">(data biner)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%2$d karakter, %1$s</item>
|
||||
<item quantity="other">%2$d karakter, %1$s</item>
|
||||
<item quantity="one">%1$s, %2$d karakter</item>
|
||||
<item quantity="other">%1$s, %2$d karakter</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Nyala/Matikan blitz</string>
|
||||
<string name="share">Bagikan</string>
|
||||
@@ -63,11 +63,11 @@
|
||||
<string name="csv_delimiter">Karakter pemisah apa yang harus digunakan (Berkas-CSV)?</string>
|
||||
<string name="delimiter_comma">Koma</string>
|
||||
<string name="delimiter_semicolon">Titik koma</string>
|
||||
<string name="csv_allow_binary">Izinkan data binari di dalam berkas keluaran?</string>
|
||||
<string name="csv_allow_binary">Izinkan data biner di dalam berkas keluaran?</string>
|
||||
<string name="no">Tidak</string>
|
||||
<string name="csv_allow_binary_message">Anda sebaiknya tidak mengizinkannya, karena akan merusak format berkas dan kemungkinan tidak bisa lagi dibaca oleh aplikasi penyunting teks.</string>
|
||||
<string name="saved_in_downloads">Simpan di dalam unduhan</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
<string name="pick_code_to_scan">Pick code to scan</string>
|
||||
<string name="rotate_image_cw">Putar gambar searah jarum jam</string>
|
||||
<string name="pick_file">Pilih berkas gambar</string>
|
||||
<string name="pick_code_to_scan">Pilih kode untuk dipindai</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<resources>
|
||||
<string name="no_camera_no_fun">Quest\'app non ha alcuna utilità senza accesso alla camera. Addio.</string>
|
||||
<string name="camera_error">Impossibile accedere alla camera. Riprovare</string>
|
||||
<string name="scan_code">Codice</string>
|
||||
<string name="no_camera_no_fun">Quest\'app non ha alcun senso senza l\'accesso alla fotocamera. Ciao.</string>
|
||||
<string name="camera_error">Impossibile accedere alla fotocamera, riprova</string>
|
||||
<string name="scan_code">Scansiona codice</string>
|
||||
<string name="compose_barcode">Crea codice a barre</string>
|
||||
<string name="decode_barcode">Decodifica codice a barre</string>
|
||||
<string name="content">Contenuto</string>
|
||||
@@ -20,44 +20,44 @@
|
||||
<string name="format">Formato</string>
|
||||
<string name="size">Dimensioni in pixel</string>
|
||||
<string name="width_by_height">%1$d×%2$d</string>
|
||||
<string name="input_content_here">Contenuto input qui</string>
|
||||
<string name="input_content_here">Inserisci il contenuto qui</string>
|
||||
<string name="encode">CODIFICA</string>
|
||||
<string name="error_no_content">Contenuto mancante</string>
|
||||
<string name="error_encoding_barcode">Il codice a barre non può essere generato</string>
|
||||
<string name="view_barcode">Vedi codice a barre</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="switch_camera">Cambia camera</string>
|
||||
<string name="switch_camera">Cambia fotocamera</string>
|
||||
<string name="history">Cronologia</string>
|
||||
<string name="preferences">Preferences</string>
|
||||
<string name="open_immediately">Skip inspection and open contents immediately</string>
|
||||
<string name="preferences">Preferenze</string>
|
||||
<string name="open_immediately">Salta l\'analisi e apri i contenuti direttamente</string>
|
||||
<string name="use_history">Salva cronologia delle scansioni</string>
|
||||
<string name="open_with_url">Apri dati sconosciuti con 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>
|
||||
<string name="no_barcode_found">Nessun codice a barre trovato</string>
|
||||
<string name="pick_list_separator">Come separare elementi di una lista?</string>
|
||||
<string name="pick_list_separator">Come separare elementi della lista?</string>
|
||||
<string name="separator_line_break">Interruzione di linea</string>
|
||||
<string name="separator_ruler">Righello</string>
|
||||
<string name="save_as_file_name">Salvare come file?</string>
|
||||
<string name="file_name">Nome del file</string>
|
||||
<string name="error_saving_binary_data">Impossibile salvare il file</string>
|
||||
<string name="error_file_exists">Il File esiste già</string>
|
||||
<string name="connect_to_wifi">Connecti al WiFi</string>
|
||||
<string name="error_file_exists">Il file esiste già</string>
|
||||
<string name="connect_to_wifi">Connetti al WiFi</string>
|
||||
<string name="wifi_config_failed">Impossibile configurare il WiFi</string>
|
||||
<string name="wifi_added">WiFi aggiunto</string>
|
||||
<string name="sms_send">Invia SMS</string>
|
||||
<string name="sms_error">Impossibile inviare SMS</string>
|
||||
<string name="tel_dial">Componi numero</string>
|
||||
<string name="tel_error">Impossibile comporre il numero</string>
|
||||
<string name="mail_send">Invia mail</string>
|
||||
<string name="mail_error">Impossibile inviare la mail</string>
|
||||
<string name="mail_send">Invia email</string>
|
||||
<string name="mail_error">Impossibile inviare l\'email</string>
|
||||
<string name="vcard_add">Aggiungi ai contatti</string>
|
||||
<string name="vcard_failed">Impossibile aggiungere ai contatti</string>
|
||||
<string name="vevent_add">Aggiungi al calendario</string>
|
||||
<string name="vevent_failed">Impossibile aggiungere al calendario</string>
|
||||
<string name="otpauth_add">Aggiungi 2FA</string>
|
||||
<string name="otpauth_error">Impossibile aggiungre il 2FA</string>
|
||||
<string name="otpauth_error">Impossibile aggiungre la 2FA</string>
|
||||
<string name="search_web">Cerca nel web</string>
|
||||
<string name="export_to_file">Esporta su file</string>
|
||||
<string name="csv_delimiter">Quale delimitatore usare (File-CSV)?</string>
|
||||
@@ -65,9 +65,9 @@
|
||||
<string name="delimiter_semicolon">Punto e virgola</string>
|
||||
<string name="csv_allow_binary">Permetti dati binari nel file di output?</string>
|
||||
<string name="no">No</string>
|
||||
<string name="csv_allow_binary_message">È consigliato non permetterlo, perché rompe il formato del file e probabilmente lo renderà non più leggibile dagli editor di testo.</string>
|
||||
<string name="csv_allow_binary_message">È consigliato non permetterlo, perché rovina il formato del file e probabilmente lo renderà non più leggibile dagli editor di testo.</string>
|
||||
<string name="saved_in_downloads">Salvato nei download</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
<string name="pick_code_to_scan">Pick code to scan</string>
|
||||
<string name="rotate_image_cw">Ruota immagine in senso orario</string>
|
||||
<string name="pick_file">Scegli file immagine</string>
|
||||
<string name="pick_code_to_scan">Scegli codice da scansionare</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<resources>
|
||||
<string name="no_camera_no_fun">没有相机权限,这个软件有啥意义。再见!</string>
|
||||
<string name="no_camera_no_fun">没有给我相机权限,扫个锤子。再见!</string>
|
||||
<string name="camera_error">无法访问相机,请重试。</string>
|
||||
<string name="scan_code">Scan code</string>
|
||||
<string name="scan_code">扫描</string>
|
||||
<string name="compose_barcode">制作条形码</string>
|
||||
<string name="decode_barcode">解码条形码</string>
|
||||
<string name="content">内容</string>
|
||||
@@ -10,12 +10,12 @@
|
||||
<item quantity="one">%2$d 字符, %1$s</item>
|
||||
<item quantity="other">%2$d 字符, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">切换闪光灯</string>
|
||||
<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="cannot_resolve_action">没有相关APP可以打开它</string>
|
||||
<string name="pick_search_engine">选择一个搜索引擎</string>
|
||||
<string name="format">编码格式</string>
|
||||
<string name="size">图片尺寸</string>
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="switch_camera">切换摄像头</string>
|
||||
<string name="history">历史</string>
|
||||
<string name="preferences">首选项</string>
|
||||
<string name="open_immediately">Skip inspection and open contents immediately</string>
|
||||
<string name="open_immediately">跳过内容展示并立即打开</string>
|
||||
<string name="use_history">保存扫描历史</string>
|
||||
<string name="open_with_url">使用URL打开未知数据</string>
|
||||
<string name="really_remove_scan">确定删除记录?</string>
|
||||
@@ -56,18 +56,18 @@
|
||||
<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>
|
||||
<string name="search_web">Search the web</string>
|
||||
<string name="export_to_file">Export to file</string>
|
||||
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
|
||||
<string name="delimiter_comma">Comma</string>
|
||||
<string name="delimiter_semicolon">Semicolon</string>
|
||||
<string name="csv_allow_binary">Allow binary data in output file?</string>
|
||||
<string name="no">No</string>
|
||||
<string name="csv_allow_binary_message">You probably don\'t want to allow that, as it will break the file format and maybe isn\'t readable by text editors anymore.</string>
|
||||
<string name="saved_in_downloads">Saved in downloads</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
<string name="pick_code_to_scan">Pick code to scan</string>
|
||||
<string name="otpauth_add">添加两步验证</string>
|
||||
<string name="otpauth_error">无法添加两步验证</string>
|
||||
<string name="search_web">在互联网中搜索</string>
|
||||
<string name="export_to_file">导出为CSV文件</string>
|
||||
<string name="csv_delimiter">使用哪个分隔符 (CSV-文件)?</string>
|
||||
<string name="delimiter_comma">逗号</string>
|
||||
<string name="delimiter_semicolon">分号</string>
|
||||
<string name="csv_allow_binary">允许输出文件中的二进制数据?</string>
|
||||
<string name="no">否</string>
|
||||
<string name="csv_allow_binary_message">您可能不想这样做,因为它会破坏文件格式,并且可能无法再由文本编辑器读取。</string>
|
||||
<string name="saved_in_downloads">已保存到下载目录</string>
|
||||
<string name="rotate_image_cw">旋转图片</string>
|
||||
<string name="pick_file">选择图片文件</string>
|
||||
<string name="pick_code_to_scan">选择扫描的编码</string>
|
||||
</resources>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<item>Google</item>
|
||||
<item>DuckDuckGo</item>
|
||||
<item>Qwant</item>
|
||||
<item>Bing</item>
|
||||
<item>Yandex</item>
|
||||
<item>OpenFoodFacts.org</item>
|
||||
<item>OpenBeautyFacts.org</item>
|
||||
<item>OpenPetFoodFacts.org</item>
|
||||
@@ -11,6 +13,8 @@
|
||||
<item>https://www.google.com/search?q=</item>
|
||||
<item>https://duckduckgo.com/?q=</item>
|
||||
<item>https://www.qwant.com/?q=</item>
|
||||
<item>https://bing.com/?q=</item>
|
||||
<item>https://yandex.com/?q=</item>
|
||||
<item>https://world.openfoodfacts.org/cgi/search.pl?search_terms=</item>
|
||||
<item>https://world.openbeautyfacts.org/cgi/search.pl?search_terms=</item>
|
||||
<item>https://world.openpetfoodfacts.org/cgi/search.pl?search_terms=</item>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<full-backup-content>
|
||||
<include domain="root" path="."/>
|
||||
</full-backup-content>
|
||||
+1
-4
@@ -1,10 +1,7 @@
|
||||
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.*
|
||||
import org.junit.Test
|
||||
|
||||
class WifiConfigurationFactoryTest {
|
||||
|
||||
+22
-5
@@ -1,9 +1,26 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.61'
|
||||
ext.tools_version = '3.5.3'
|
||||
ext.build_tools_version = '28.0.3'
|
||||
ext.sdk_version = 29
|
||||
ext.support_version = '25.3.1'
|
||||
// Since RenderScript can no longer be compiled on macOS Catalina
|
||||
// because Catalina cannot run 32bit binaries and Google failed
|
||||
// to provide a 64bit compiler in time. Now, as if that wasn't
|
||||
// bad enough, the new build tools that provide a 64bit compiler
|
||||
// don't work on any other system than macOS unfortunately.
|
||||
ext.is_catalina = {
|
||||
if (System.properties['os.name'] == 'Mac OS X') {
|
||||
def numbers = System.properties['os.version'].split('\\.')
|
||||
if (numbers.length > 1) {
|
||||
return numbers[1].toInteger() >= 15
|
||||
}
|
||||
}
|
||||
return false
|
||||
}()
|
||||
|
||||
ext {
|
||||
kotlin_version = '1.3.61'
|
||||
tools_version = '3.6.1'
|
||||
build_tools_version = ext.is_catalina ? '29.0.3' : '28.0.3'
|
||||
sdk_version = 29
|
||||
support_version = '25.3.1'
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
|
||||
Reference in New Issue
Block a user