Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import android.widget.SeekBar
import android.widget.Spinner
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
Expand All @@ -47,6 +46,8 @@ import de.markusfisch.android.binaryeye.app.hasCameraPermission
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.automation.runAutomatedActions
import de.markusfisch.android.binaryeye.bluetooth.sendBluetoothAsync
import de.markusfisch.android.binaryeye.camera.availableDefaultCameras
import de.markusfisch.android.binaryeye.camera.cameraSelector
import de.markusfisch.android.binaryeye.content.copyToClipboard
import de.markusfisch.android.binaryeye.content.startIntentOrToast
import de.markusfisch.android.binaryeye.database.toScan
Expand All @@ -56,6 +57,7 @@ import de.markusfisch.android.binaryeye.graphics.mapViewYToFrame
import de.markusfisch.android.binaryeye.graphics.setCovered
import de.markusfisch.android.binaryeye.graphics.setFrameRoi
import de.markusfisch.android.binaryeye.graphics.setFrameToView
import de.markusfisch.android.binaryeye.kdeconnect.sendToKdeConnect
import de.markusfisch.android.binaryeye.media.releaseToneGenerators
import de.markusfisch.android.binaryeye.net.isScanDeeplink
import de.markusfisch.android.binaryeye.net.sendAsync
Expand Down Expand Up @@ -112,7 +114,7 @@ class CameraActivity : AppCompatActivity() {
private var returnResult = false
private var returnUrlTemplate: String? = null
private var finishAfterShowingResult = false
private var frontFacing = false
private var selectedCamera = prefs.defaultCamera
private var bulkMode = prefs.bulkMode
private var restrictFormat: String? = null
private var searchTerm: Regex? = null
Expand Down Expand Up @@ -343,15 +345,15 @@ class CameraActivity : AppCompatActivity() {
override fun onRestoreInstanceState(savedState: Bundle) {
super.onRestoreInstanceState(savedState)
zoomBar.progress = savedState.getInt(ZOOM_LEVEL)
frontFacing = savedState.getBoolean(FRONT_FACING)
selectedCamera = savedState.getString(SELECTED_CAMERA, selectedCamera)
bulkMode = savedState.getBoolean(BULK_MODE)
restrictFormat = savedState.getString(RESTRICT_FORMAT)
searchTerm = savedState.getString(SEARCH_TERM)?.toRegex()
}

override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(ZOOM_LEVEL, zoomBar.progress)
outState.putBoolean(FRONT_FACING, frontFacing)
outState.putString(SELECTED_CAMERA, selectedCamera)
outState.putBoolean(BULK_MODE, bulkMode)
outState.putString(RESTRICT_FORMAT, restrictFormat)
outState.putString(SEARCH_TERM, searchTerm?.toString())
Expand Down Expand Up @@ -450,7 +452,10 @@ class CameraActivity : AppCompatActivity() {
}

private fun switchCamera() {
frontFacing = frontFacing xor true
val cameras = availableDefaultCameras(this)
selectedCamera = cameras[
(cameras.indexOf(selectedCamera) + 1).mod(cameras.size)
]
bindCameraUseCases()
}

Expand Down Expand Up @@ -738,15 +743,17 @@ class CameraActivity : AppCompatActivity() {
analyzeImage(image)
}

val cameraSelector = CameraSelector.Builder()
.requireLensFacing(
if (frontFacing) {
CameraSelector.LENS_FACING_FRONT
} else {
CameraSelector.LENS_FACING_BACK
}
)
.build()
var cameraSelector = cameraSelector(selectedCamera)
if (!provider.hasCamera(cameraSelector)) {
selectedCamera = prefs.defaultCamera
cameraSelector = cameraSelector(selectedCamera)
}
if (!provider.hasCamera(cameraSelector)) {
selectedCamera = availableDefaultCameras(this)
.firstOrNull { provider.hasCamera(cameraSelector(it)) }
?: selectedCamera
cameraSelector = cameraSelector(selectedCamera)
}

try {
provider.unbindAll()
Expand Down Expand Up @@ -1017,7 +1024,7 @@ class CameraActivity : AppCompatActivity() {
private const val PICK_FILE_RESULT_CODE = 1
private const val INITIAL_ZOOM = 0
private const val ZOOM_LEVEL = "zoom"
private const val FRONT_FACING = "front_facing"
private const val SELECTED_CAMERA = "selected_camera"
private const val BULK_MODE = "bulk_mode"
private const val RESTRICT_FORMAT = "restrict_format"
private const val SEARCH_TERM = "search_term"
Expand Down Expand Up @@ -1079,6 +1086,9 @@ fun Activity.showResult(
)
}
}
if (prefs.sendScanKdeConnect && !bulkMode) {
sendToKdeConnect(scan)
}
if (runAutomatedActions(scan)) {
return
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package de.markusfisch.android.binaryeye.camera

import android.annotation.SuppressLint
import android.content.Context
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import androidx.camera.core.CameraSelector
import de.markusfisch.android.binaryeye.R

const val DEFAULT_CAMERA_BACK = "back"
const val DEFAULT_CAMERA_FRONT = "front"
const val DEFAULT_CAMERA_OTHER = "other"

fun availableDefaultCameras(context: Context): List<String> {
val lensFacings = try {
(context.getSystemService(Context.CAMERA_SERVICE) as CameraManager)
.run {
cameraIdList.mapNotNull { id ->
getCameraCharacteristics(id)
.get(CameraCharacteristics.LENS_FACING)
}
}.toSet()
} catch (_: Exception) {
emptySet()
}
return buildList {
if (lensFacings.isEmpty() ||
lensFacings.contains(CameraCharacteristics.LENS_FACING_BACK)
) {
add(DEFAULT_CAMERA_BACK)
}
if (lensFacings.contains(CameraCharacteristics.LENS_FACING_FRONT)) {
add(DEFAULT_CAMERA_FRONT)
}
if (lensFacings.contains(CameraCharacteristics.LENS_FACING_EXTERNAL)) {
add(DEFAULT_CAMERA_OTHER)
}
}
}

fun defaultCameraEntries(context: Context, values: List<String>) =
values.map {
when (it) {
DEFAULT_CAMERA_FRONT -> context.getString(R.string.default_camera_front)
DEFAULT_CAMERA_OTHER -> context.getString(R.string.default_camera_other)
else -> context.getString(R.string.default_camera_back)
}
}.toTypedArray()

@SuppressLint("UnsafeOptInUsageError")
fun cameraSelector(camera: String) = CameraSelector.Builder()
.requireLensFacing(
when (camera) {
DEFAULT_CAMERA_FRONT -> CameraSelector.LENS_FACING_FRONT
DEFAULT_CAMERA_OTHER -> CameraSelector.LENS_FACING_EXTERNAL
else -> CameraSelector.LENS_FACING_BACK
}
)
.build()
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ fun Context.startIntent(intent: Intent): Boolean = try {
true
} catch (_: ActivityNotFoundException) {
false
} catch (_: SecurityException) {
false
}

fun Context.openUrl(url: String, silent: Boolean = false): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import de.markusfisch.android.binaryeye.adapter.prettifyFormatName
import de.markusfisch.android.binaryeye.app.hasBluetoothPermission
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.bluetooth.setBluetoothHosts
import de.markusfisch.android.binaryeye.camera.availableDefaultCameras
import de.markusfisch.android.binaryeye.camera.defaultCameraEntries
import de.markusfisch.android.binaryeye.media.beepConfirm
import de.markusfisch.android.binaryeye.preference.Preferences
import de.markusfisch.android.binaryeye.preference.UrlPreference
Expand Down Expand Up @@ -101,6 +103,7 @@ class PreferencesFragment : PreferenceFragmentCompat() {
setIcons()

wireBeepTonePicker()
setDefaultCameras()
wireProfiles()
wireAutomatedActions()
wireIgnoreCodes()
Expand Down Expand Up @@ -142,6 +145,19 @@ class PreferencesFragment : PreferenceFragmentCompat() {
}
}

private fun setDefaultCameras() {
findPreference<ListPreference>(DEFAULT_CAMERA)?.apply {
val values = availableDefaultCameras(requireContext())
entries = defaultCameraEntries(requireContext(), values)
entryValues = values.toTypedArray()
if (!values.contains(value)) {
value = values.firstOrNull()
}
isVisible = values.size > 1
setSummary(this)
}
}

private fun wireAutomatedActions() {
findPreference<Preference>(AUTOMATED_ACTIONS)?.apply {
updateAutomatedActionsSummary(this)
Expand Down Expand Up @@ -340,6 +356,7 @@ class PreferencesFragment : PreferenceFragmentCompat() {
setIcon("auto_rotate", R.drawable.ic_action_down)
setIcon("try_harder", R.drawable.ic_action_search)
setIcon("bulk_mode", R.drawable.ic_action_bulk_mode)
setIcon(DEFAULT_CAMERA, R.drawable.ic_action_switch_camera)
setIcon("bulk_mode_delay", R.drawable.ic_action_delay)
setIcon("show_toast_in_bulk_mode", R.drawable.ic_action_toast)
setIcon("vibrate", R.drawable.ic_action_vibrate)
Expand All @@ -356,6 +373,7 @@ class PreferencesFragment : PreferenceFragmentCompat() {
setIcon("send_scan_device_id", R.drawable.ic_label)
setIcon(SEND_SCAN_BLUETOOTH, R.drawable.ic_action_bluetooth)
setIcon(SEND_SCAN_BLUETOOTH_HOST, R.drawable.ic_action_bluetooth)
setIcon(SEND_SCAN_KDE_CONNECT, R.drawable.ic_action_forward)
setIcon("open_immediately", R.drawable.ic_action_open)
setIcon("strip_tracking_params", R.drawable.ic_action_remove)
setIcon("show_meta_data", R.drawable.ic_action_info)
Expand Down Expand Up @@ -482,9 +500,11 @@ class PreferencesFragment : PreferenceFragmentCompat() {
private const val CLEAR_NETWORK_SUGGESTIONS = "clear_network_suggestions"
private const val CUSTOM_LOCALE = "custom_locale"
private const val DYNAMIC_COLORS = "dynamic_colors"
private const val DEFAULT_CAMERA = "default_camera"
private const val IGNORE_CODES = "ignore_codes"
private const val SEND_SCAN_BLUETOOTH = "send_scan_bluetooth"
private const val SEND_SCAN_BLUETOOTH_HOST = "send_scan_bluetooth_host"
private const val SEND_SCAN_KDE_CONNECT = "send_scan_kde_connect"
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package de.markusfisch.android.binaryeye.kdeconnect

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import de.markusfisch.android.binaryeye.content.startIntentOrToast
import de.markusfisch.android.binaryeye.database.Scan

private const val KDE_CONNECT_PACKAGE = "org.kde.kdeconnect_tp"
private const val KDE_CONNECT_KEYSTROKES_ACTIVITY =
"org.kde.kdeconnect.plugins.mousepad.SendKeystrokesToHostActivity"
private const val KEYSTROKES_MIME_TYPE = "text/x-keystrokes"

fun Context.sendToKdeConnect(scan: Scan): Boolean {
if (scan.text.isEmpty()) {
return false
}
return startIntentOrToast(createKdeConnectIntent(scan.text))
}

fun createKdeConnectIntent(text: String): Intent {
return Intent(Intent.ACTION_SEND).apply {
component = ComponentName(
KDE_CONNECT_PACKAGE,
KDE_CONNECT_KEYSTROKES_ACTIVITY
)
type = KEYSTROKES_MIME_TYPE
putExtra(Intent.EXTRA_TEXT, text)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ class Preferences {
apply(BULK_MODE, value)
field = value
}
var defaultCamera = "back"
set(value) {
apply(DEFAULT_CAMERA, value)
field = value
}
var bulkModeDelay = "500"
set(value) {
apply(BULK_MODE_DELAY, value)
Expand Down Expand Up @@ -226,6 +231,11 @@ class Preferences {
apply(SEND_SCAN_BLUETOOTH_HOST, value)
field = value
}
var sendScanKdeConnect = false
set(value) {
apply(SEND_SCAN_KDE_CONNECT, value)
field = value
}
var customLocale: String = ""
set(value) {
// Make sure this setting is written immediately because
Expand Down Expand Up @@ -372,6 +382,7 @@ class Preferences {
json.put(AUTO_ROTATE, p, defaults.autoRotate)
json.put(TRY_HARDER, p, defaults.tryHarder)
json.put(BULK_MODE, p, defaults.bulkMode)
json.put(DEFAULT_CAMERA, p, defaults.defaultCamera)
json.put(BULK_MODE_DELAY, p, defaults.bulkModeDelay)
json.put(SHOW_TOAST_IN_BULK_MODE, p, defaults.showToastInBulkMode)
json.put(VIBRATE, p, defaults.vibrate)
Expand All @@ -398,6 +409,7 @@ class Preferences {
json.put(SEND_SCAN_DEVICE_ID, p, defaults.sendScanDeviceId)
json.put(SEND_SCAN_BLUETOOTH, p, defaults.sendScanBluetooth)
json.put(SEND_SCAN_BLUETOOTH_HOST, p, defaults.sendScanBluetoothHost)
json.put(SEND_SCAN_KDE_CONNECT, p, defaults.sendScanKdeConnect)
json.put(CUSTOM_LOCALE, p, defaults.customLocale)
json.put(INDEX_OF_LAST_SELECTED_FORMAT, p, defaults.indexOfLastSelectedFormat)
json.put(INDEX_OF_LAST_SELECTED_EC_LEVEL, p, defaults.indexOfLastSelectedEcLevel)
Expand Down Expand Up @@ -471,6 +483,7 @@ class Preferences {
putBoolean(AUTO_ROTATE, json)
putBoolean(TRY_HARDER, json)
putBoolean(BULK_MODE, json)
putString(DEFAULT_CAMERA, json)
putString(BULK_MODE_DELAY, json)
putBoolean(SHOW_TOAST_IN_BULK_MODE, json)
putBoolean(VIBRATE, json)
Expand All @@ -497,6 +510,7 @@ class Preferences {
putString(SEND_SCAN_DEVICE_ID, json)
putBoolean(SEND_SCAN_BLUETOOTH, json)
putString(SEND_SCAN_BLUETOOTH_HOST, json)
putBoolean(SEND_SCAN_KDE_CONNECT, json)
putString(CUSTOM_LOCALE, json)
putInt(INDEX_OF_LAST_SELECTED_FORMAT, json)
putInt(INDEX_OF_LAST_SELECTED_EC_LEVEL, json)
Expand Down Expand Up @@ -553,6 +567,9 @@ class Preferences {
autoRotate = preferences.getBoolean(AUTO_ROTATE, autoRotate)
tryHarder = preferences.getBoolean(TRY_HARDER, tryHarder)
bulkMode = preferences.getBoolean(BULK_MODE, bulkMode)
preferences.getString(DEFAULT_CAMERA, defaultCamera)?.also {
defaultCamera = it
}
bulkModeDelay = preferences.getString(
BULK_MODE_DELAY,
bulkModeDelay
Expand Down Expand Up @@ -648,6 +665,10 @@ class Preferences {
)?.also {
sendScanBluetoothHost = it
}
sendScanKdeConnect = preferences.getBoolean(
SEND_SCAN_KDE_CONNECT,
sendScanKdeConnect
)
preferences.getString(CUSTOM_LOCALE, customLocale)?.also {
customLocale = it
}
Expand Down Expand Up @@ -796,6 +817,7 @@ class Preferences {
putBoolean(AUTO_ROTATE, defaults.autoRotate)
putBoolean(TRY_HARDER, defaults.tryHarder)
putBoolean(BULK_MODE, defaults.bulkMode)
putString(DEFAULT_CAMERA, defaults.defaultCamera)
putString(BULK_MODE_DELAY, defaults.bulkModeDelay)
putBoolean(SHOW_TOAST_IN_BULK_MODE, defaults.showToastInBulkMode)
putBoolean(VIBRATE, defaults.vibrate)
Expand All @@ -822,6 +844,7 @@ class Preferences {
putString(SEND_SCAN_DEVICE_ID, defaults.sendScanDeviceId)
putBoolean(SEND_SCAN_BLUETOOTH, defaults.sendScanBluetooth)
putString(SEND_SCAN_BLUETOOTH_HOST, defaults.sendScanBluetoothHost)
putBoolean(SEND_SCAN_KDE_CONNECT, defaults.sendScanKdeConnect)
putString(CUSTOM_LOCALE, defaults.customLocale)
putInt(INDEX_OF_LAST_SELECTED_FORMAT, defaults.indexOfLastSelectedFormat)
putInt(INDEX_OF_LAST_SELECTED_EC_LEVEL, defaults.indexOfLastSelectedEcLevel)
Expand Down Expand Up @@ -903,6 +926,7 @@ class Preferences {
private const val AUTO_ROTATE = "auto_rotate"
private const val TRY_HARDER = "try_harder"
private const val BULK_MODE = "bulk_mode"
private const val DEFAULT_CAMERA = "default_camera"
private const val BULK_MODE_DELAY = "bulk_mode_delay"
private const val SHOW_TOAST_IN_BULK_MODE = "show_toast_in_bulk_mode"
private const val VIBRATE = "vibrate"
Expand All @@ -929,6 +953,7 @@ class Preferences {
private const val SEND_SCAN_DEVICE_ID = "send_scan_device_id"
private const val SEND_SCAN_BLUETOOTH = "send_scan_bluetooth"
private const val SEND_SCAN_BLUETOOTH_HOST = "send_scan_bluetooth_host"
private const val SEND_SCAN_KDE_CONNECT = "send_scan_kde_connect"
private const val CUSTOM_LOCALE = "custom_locale"
private const val INDEX_OF_LAST_SELECTED_FORMAT = "index_of_last_selected_format"
private const val INDEX_OF_LAST_SELECTED_EC_LEVEL = "index_of_last_selected_ec_level"
Expand Down
Loading