From 5028b95623faf06d49daab8ed793280fc67bf601 Mon Sep 17 00:00:00 2001 From: VincentKobz Date: Wed, 17 Apr 2024 15:00:29 +0200 Subject: [PATCH] feat: Extract camera scanner from core library as a new activity --- demoscannerapp/build.gradle | 1 + enioka_scan/build.gradle | 16 +- enioka_scan/src/main/AndroidManifest.xml | 7 - .../activities/ManualInputFragment.java | 2 +- .../activities/ScannerCompatActivity.java | 224 ++--------- enioka_scan_camera/.gitignore | 1 + enioka_scan_camera/build.gradle | 50 +++ .../src/main/AndroidManifest.xml | 19 + .../scanner/sdk}/camera/CameraApiLevel.java | 2 +- .../sdk}/camera/CameraBarcodeScanView.java | 8 +- .../camera/CameraBarcodeScanViewBase.java | 15 +- .../camera/CameraBarcodeScanViewScanner.java | 2 +- .../sdk}/camera/CameraBarcodeScanViewV1.java | 5 +- .../sdk}/camera/CameraBarcodeScanViewV2.java | 11 +- .../sdk/camera/CameraCompatActivity.java | 369 ++++++++++++++++++ .../sdk}/camera/CameraPreviewSurfaceView.java | 4 +- .../scanner/sdk}/camera/CameraReader.java | 2 +- .../scanner/sdk}/camera/CroppedPicture.java | 2 +- .../scanner/sdk}/camera/FrameAnalyser.java | 4 +- .../sdk}/camera/FrameAnalyserManager.java | 2 +- .../sdk}/camera/FrameAnalysisContext.java | 2 +- .../scanner/sdk}/camera/Resolution.java | 2 +- .../scanner/sdk}/camera/ScannerCallback.java | 2 +- .../scanner/sdk}/camera/TargetView.java | 8 +- .../sdk}/camera/ViewHelpersPreferences.java | 2 +- .../sdk}/camera/ViewHelpersResolution.java | 2 +- .../sdk}/camera/ZBarFrameAnalyser.java | 2 +- .../scanner/sdk}/camera/ZBarScanView.java | 2 +- .../sdk}/camera/ZXingFrameAnalyser.java | 2 +- .../main/res/drawable-hdpi/icn_flash_off.png | Bin 0 -> 2381 bytes .../res/drawable-hdpi/icn_flash_off_on.png | Bin 0 -> 2062 bytes .../main/res/drawable-mdpi/icn_flash_off.png | Bin 0 -> 1574 bytes .../res/drawable-mdpi/icn_flash_off_on.png | Bin 0 -> 1311 bytes .../main/res/drawable-xhdpi/icn_flash_off.png | Bin 0 -> 3137 bytes .../res/drawable-xhdpi/icn_flash_off_on.png | Bin 0 -> 2729 bytes .../res/drawable-xxhdpi/icn_flash_off.png | Bin 0 -> 4925 bytes .../res/drawable-xxhdpi/icn_flash_off_on.png | Bin 0 -> 4360 bytes .../res/drawable-xxxhdpi/icn_flash_off.png | Bin 0 -> 6967 bytes .../res/drawable-xxxhdpi/icn_flash_off_on.png | Bin 0 -> 5871 bytes .../src/main/res/layout/activity_main_alt.xml | 94 +++++ .../src/main/res/layout/dropdown_item.xml | 33 ++ .../res/layout/fragment_scan_manual_input.xml | 56 +++ .../src/main/res/values-fr/strings.xml | 38 ++ .../src/main/res/values/attrs.xml | 28 ++ .../src/main/res/values/colors.xml | 4 + .../src/main/res/values/ids.xml | 4 + .../src/main/res/values/strings.xml | 45 +++ settings.gradle | 1 + 48 files changed, 823 insertions(+), 250 deletions(-) create mode 100644 enioka_scan_camera/.gitignore create mode 100644 enioka_scan_camera/build.gradle create mode 100644 enioka_scan_camera/src/main/AndroidManifest.xml rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/CameraApiLevel.java (57%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/CameraBarcodeScanView.java (99%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/CameraBarcodeScanViewBase.java (98%) rename {enioka_scan => enioka_scan_camera}/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewScanner.java (98%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/CameraBarcodeScanViewV1.java (99%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/CameraBarcodeScanViewV2.java (99%) create mode 100644 enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraCompatActivity.java rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/CameraPreviewSurfaceView.java (97%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/CameraReader.java (88%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/CroppedPicture.java (84%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/FrameAnalyser.java (95%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/FrameAnalyserManager.java (99%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/FrameAnalysisContext.java (89%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/Resolution.java (99%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/ScannerCallback.java (96%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/TargetView.java (97%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/ViewHelpersPreferences.java (98%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/ViewHelpersResolution.java (99%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/ZBarFrameAnalyser.java (99%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/ZBarScanView.java (91%) rename {enioka_scan/src/main/java/com/enioka/scanner => enioka_scan_camera/src/main/java/com/enioka/scanner/sdk}/camera/ZXingFrameAnalyser.java (99%) create mode 100644 enioka_scan_camera/src/main/res/drawable-hdpi/icn_flash_off.png create mode 100644 enioka_scan_camera/src/main/res/drawable-hdpi/icn_flash_off_on.png create mode 100644 enioka_scan_camera/src/main/res/drawable-mdpi/icn_flash_off.png create mode 100644 enioka_scan_camera/src/main/res/drawable-mdpi/icn_flash_off_on.png create mode 100644 enioka_scan_camera/src/main/res/drawable-xhdpi/icn_flash_off.png create mode 100644 enioka_scan_camera/src/main/res/drawable-xhdpi/icn_flash_off_on.png create mode 100644 enioka_scan_camera/src/main/res/drawable-xxhdpi/icn_flash_off.png create mode 100644 enioka_scan_camera/src/main/res/drawable-xxhdpi/icn_flash_off_on.png create mode 100644 enioka_scan_camera/src/main/res/drawable-xxxhdpi/icn_flash_off.png create mode 100644 enioka_scan_camera/src/main/res/drawable-xxxhdpi/icn_flash_off_on.png create mode 100644 enioka_scan_camera/src/main/res/layout/activity_main_alt.xml create mode 100644 enioka_scan_camera/src/main/res/layout/dropdown_item.xml create mode 100644 enioka_scan_camera/src/main/res/layout/fragment_scan_manual_input.xml create mode 100644 enioka_scan_camera/src/main/res/values-fr/strings.xml create mode 100644 enioka_scan_camera/src/main/res/values/attrs.xml create mode 100644 enioka_scan_camera/src/main/res/values/colors.xml create mode 100644 enioka_scan_camera/src/main/res/values/ids.xml create mode 100644 enioka_scan_camera/src/main/res/values/strings.xml diff --git a/demoscannerapp/build.gradle b/demoscannerapp/build.gradle index 200245ed..4aaea072 100644 --- a/demoscannerapp/build.gradle +++ b/demoscannerapp/build.gradle @@ -27,6 +27,7 @@ android { dependencies { // Reference our own library, directly compiled from its project implementation project(':enioka_scan'); + implementation project(':enioka_scan_camera'); if (gradle.ext.withHoneywell) { implementation project(':enioka_scan_honeywell'); diff --git a/enioka_scan/build.gradle b/enioka_scan/build.gradle index 05c1539e..ea40394e 100644 --- a/enioka_scan/build.gradle +++ b/enioka_scan/build.gradle @@ -35,14 +35,14 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.android.support.constraint:constraint-layout:2.0.4' - // ZBAR & ZXING (Zebra Crossing) = camera. From Maven Central. - api('me.dm7.barcodescanner:zbar:1.9.8') { - transitive = false - } - api('me.dm7.barcodescanner:core:1.9.8') { - transitive = false - } - api 'com.google.zxing:core:3.5.1' +// // ZBAR & ZXING (Zebra Crossing) = camera. From Maven Central. +// api('me.dm7.barcodescanner:zbar:1.9.8') { +// transitive = false +// } +// api('me.dm7.barcodescanner:core:1.9.8') { +// transitive = false +// } +// api 'com.google.zxing:core:3.5.1' // Test things (useless for now) androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { diff --git a/enioka_scan/src/main/AndroidManifest.xml b/enioka_scan/src/main/AndroidManifest.xml index 0b081c9c..1bd6b582 100644 --- a/enioka_scan/src/main/AndroidManifest.xml +++ b/enioka_scan/src/main/AndroidManifest.xml @@ -29,12 +29,6 @@ - - @@ -42,7 +36,6 @@ android:name="android.hardware.bluetooth" android:required="false" /> - diff --git a/enioka_scan/src/main/java/com/enioka/scanner/activities/ManualInputFragment.java b/enioka_scan/src/main/java/com/enioka/scanner/activities/ManualInputFragment.java index fb2676c2..2100b72c 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/activities/ManualInputFragment.java +++ b/enioka_scan/src/main/java/com/enioka/scanner/activities/ManualInputFragment.java @@ -76,7 +76,7 @@ public void onAttach(Context activity) { // The host should be an activity implementing a barcode listener. cb = (ScannerClient) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement ScannerDataCallback"); + throw new ClassCastException(activity.toString() + " must implement ScannerClient"); } } diff --git a/enioka_scan/src/main/java/com/enioka/scanner/activities/ScannerCompatActivity.java b/enioka_scan/src/main/java/com/enioka/scanner/activities/ScannerCompatActivity.java index 7156fd72..3b7304c0 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/activities/ScannerCompatActivity.java +++ b/enioka_scan/src/main/java/com/enioka/scanner/activities/ScannerCompatActivity.java @@ -22,7 +22,6 @@ import android.util.Log; import android.view.View; import android.widget.ImageButton; -import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; @@ -30,35 +29,23 @@ import com.enioka.scanner.api.Scanner; import com.enioka.scanner.api.ScannerLedColor; import com.enioka.scanner.api.callbacks.ScannerStatusCallback; -import com.enioka.scanner.api.proxies.ScannerDataCallbackProxy; -import com.enioka.scanner.api.proxies.ScannerStatusCallbackProxy; -import com.enioka.scanner.camera.CameraBarcodeScanView; -import com.enioka.scanner.camera.CameraReader; import com.enioka.scanner.data.Barcode; -import com.enioka.scanner.data.BarcodeType; -import com.enioka.scanner.helpers.Common; -import com.enioka.scanner.sdk.camera.CameraBarcodeScanViewScanner; import com.enioka.scanner.service.ScannerClient; import com.enioka.scanner.service.ScannerService; import com.enioka.scanner.service.ScannerServiceApi; import com.enioka.scanner.service.ScannerServiceBinderHelper; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Objects; -import java.util.Set; /** * A helper activity which implements all scan functions: laser, camera, HID.

Basic usage is trivial : just inherit this class, and that's all.
* You may want to override {@link #onData(List)} to get barcode data, and {@link #onStatusChanged(Scanner, ScannerStatusCallback.Status)} to display status messages from the scanners.
- * It is also useful to change inside onCreate {@link #layoutIdLaser} and {@link #layoutIdCamera} to a layout ID (from R.id...) corresponding to your application. + * It is also useful to change inside onCreate {@link #layoutIdLaser} to a layout ID (from R.id...) corresponding to your application. * By default, a basic test layout is provided.
- * Also, {@link #cameraViewId} points to the camera view inside your camera layout. */ public class ScannerCompatActivity extends AppCompatActivity implements ScannerClient { protected final static String LOG_TAG = "ScannerActivity"; - protected final static int PERMISSION_REQUEST_ID_CAMERA = 1790; protected final static int PERMISSION_REQUEST_ID_BT = 1792; /** @@ -71,11 +58,6 @@ public class ScannerCompatActivity extends AppCompatActivity implements ScannerC */ protected boolean enableScan = true; - /** - * Helper to go directly to camera (used on reload, such as after permission change). - */ - protected boolean goToCamera = false; - /** * Check the app's bluetooth permissions. This variable does not affect scanner search options. */ @@ -85,19 +67,6 @@ public class ScannerCompatActivity extends AppCompatActivity implements ScannerC * The layout to use when using a laser or external keyboard. */ protected int layoutIdLaser = R.layout.activity_main; - /** - * The layout to use when using camera scanner. - */ - protected int layoutIdCamera = R.layout.activity_main_alt; - /** - * Use {@link #cameraViewId} instead. - */ - @Deprecated - protected Integer zbarViewId = null; - /** - * The ID of the {@link CameraBarcodeScanView} inside the {@link #layoutIdCamera} layout. - */ - protected int cameraViewId = R.id.camera_scan_view; /** * The ID of the ImageButton on which to press to manually switch to camera mode. @@ -109,13 +78,6 @@ public class ScannerCompatActivity extends AppCompatActivity implements ScannerC */ protected int flashlightViewId = R.id.scanner_flashlight; - /** - * The ID of the optional ImageButton on which to press to toggle the zxing/zbar camera scan library. - */ - protected int scannerModeToggleViewId = R.id.scanner_switch_zxing; - - protected int scannerModeTogglePauseId = R.id.scanner_switch_pause; - protected int keyboardOpenViewId = R.id.scanner_bt_keyboard; /** @@ -139,11 +101,6 @@ public class ScannerCompatActivity extends AppCompatActivity implements ScannerC protected ScannerServiceApi scannerService; private boolean serviceBound = false; - /** - * Optional camera scanner - */ - protected CameraBarcodeScanViewScanner cameraScanner; - //////////////////////////////////////////////////////////////////////////////////////////////// // Activity lifecycle callbacks @@ -156,12 +113,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { //Common.askForPermission(this); // NO: this actually pauses then resumes the activity. // Set content immediately - that way our callbacks can draw on the layout. - setViewContent(); - - // Ascending compatibility - if (zbarViewId != null) { - cameraViewId = zbarViewId; - } + setContentView(layoutIdLaser); // init fields serviceBound = false; @@ -194,11 +146,6 @@ protected void onResume() { return; } - if (goToCamera) { - Log.i(LOG_TAG, "Resuming scanner activity in camera mode"); - initCamera(); - return; - } Log.i(LOG_TAG, "Resuming scanner activity - scanners will be (re)connected"); // Reset data fields @@ -229,10 +176,7 @@ protected void onPause() { if (serviceBound) { scannerService.pause(); } - if (cameraScanner != null) { - cameraScanner.disconnect(); - cameraScanner = null; - } + super.onPause(); } @@ -253,15 +197,6 @@ protected void onDestroy() { serviceBound = false; } - private void setViewContent() { - if (enableScan && goToCamera && hasPermissionSet(this, PERMISSIONS_CAMERA)) { - // Can only add/open a camera view if camera is allowed. - setContentView(layoutIdCamera); - } else { - setContentView(layoutIdLaser); - } - } - //////////////////////////////////////////////////////////////////////////////////////////////// // Scanner service init @@ -330,68 +265,27 @@ public void setAutocompletionItems(List items, int threshold) { this.threshold = threshold; } - //////////////////////////////////////////////////////////////////////////////////////////////// // Camera //////////////////////////////////////////////////////////////////////////////////////////////// - protected void initCamera() { - Log.i(LOG_TAG, "Giving up on laser, going to camera"); - if (!Common.hasCamera(this)) { - Log.i(LOG_TAG, "No camera available on device"); - Toast.makeText(this, R.string.scanner_status_no_camera, Toast.LENGTH_SHORT).show(); - return; - } + public void startCameraActivity() { + try { + Class cameraScannerActivity = Class.forName("com.enioka.scanner.sdk.camera.CameraCompatActivity"); + Intent intent = new Intent(this, cameraScannerActivity); - boolean activityStartedInCameraMode = goToCamera; - goToCamera = true; - - if (hasPermissionSet(this, PERMISSIONS_CAMERA)) { - if (!activityStartedInCameraMode) { - // The view needs permissions BEFORE initializing. And it initializes as soon as the layout is set. - setContentView(layoutIdCamera); - } - initCameraScanner(); - - // Reinit text - if (findViewById(R.id.scanner_text_scanner_status) != null) { - TextView tv = findViewById(R.id.scanner_text_scanner_status); - tv.setText(""); + // Add extras + if (getServiceInitExtras() != null) { + intent.putExtras(getServiceInitExtras()); } - } else { - requestPermissionSet(this, PERMISSIONS_CAMERA, PERMISSION_REQUEST_ID_CAMERA); - } - } - - private void initCameraScanner() { - if (cameraScanner != null) { - return; - } - // TODO: should be in camera constructor, not here... - CameraBarcodeScanView cameraView = findViewById(cameraViewId); - if (cameraView == null) { - Toast.makeText(this, R.string.scanner_status_no_camera, Toast.LENGTH_SHORT).show(); - return; - } - - final Set symbologies = new HashSet<>(); - if (getIntent().getExtras() != null && getIntent().getExtras().getStringArray(ScannerServiceApi.EXTRA_SYMBOLOGY_SELECTION) != null) { - for (final String symbology : Objects.requireNonNull(getIntent().getExtras().getStringArray(ScannerServiceApi.EXTRA_SYMBOLOGY_SELECTION))) { - symbologies.add(BarcodeType.valueOf(symbology)); + if (getIntent().getExtras() != null) { + intent.putExtras(getIntent().getExtras()); } - } - if (symbologies.isEmpty()) { - symbologies.add(BarcodeType.CODE128); - } - cameraScanner = new CameraBarcodeScanViewScanner(cameraView, new ScannerDataCallbackProxy((s, data) -> ScannerCompatActivity.this.onData(data)), new ScannerStatusCallbackProxy(this), symbologies); - if (findViewById(R.id.scanner_text_last_scan) != null) { - ((TextView) findViewById(R.id.scanner_text_last_scan)).setText(null); + this.startActivity(intent); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); } - displayTorch(); - displayManualInputButton(); - displayCameraReaderToggle(); - displayCameraPauseToggle(); } @@ -402,27 +296,13 @@ private void initCameraScanner() { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - switch (requestCode) { - case PERMISSION_REQUEST_ID_CAMERA: { - // If request is cancelled, the result arrays are empty. - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - goToCamera = true; // in case the activity was paused by the permission request dialog - setViewContent(); - initCameraScanner(); - } else { - Toast.makeText(this, R.string.scanner_status_no_camera, Toast.LENGTH_SHORT).show(); + if (requestCode == PERMISSION_REQUEST_ID_BT) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (!useBluetooth || hasPermissionSet(this, PERMISSIONS_BT)) { + bindAndStartService(); } - break; - } - case PERMISSION_REQUEST_ID_BT: { - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - if (!useBluetooth || hasPermissionSet(this, PERMISSIONS_BT)) { - bindAndStartService(); - } - } else { - Toast.makeText(this, R.string.scanner_status_DISABLED, Toast.LENGTH_SHORT).show(); - } - break; + } else { + Toast.makeText(this, R.string.scanner_status_DISABLED, Toast.LENGTH_SHORT).show(); } } } @@ -446,8 +326,8 @@ public void onScannerInitEnded(int scannerCount) { Log.i(LOG_TAG, "Activity can now use all received scanners (" + scannerCount + ")"); if (scannerCount == 0 && !laserModeOnly && enableScan) { - // In that case try to connect to a camera. - initCamera(); + // In that case try to connect to a camera by launching the camera activity. + startCameraActivity(); } displayTorch(); @@ -483,7 +363,6 @@ public void onData(List data) { } } - //////////////////////////////////////////////////////////////////////////////////////////////// // Button and input initialization //////////////////////////////////////////////////////////////////////////////////////////////// @@ -499,20 +378,13 @@ private void displayTorch() { toggleTorch(); - if (cameraScanner != null) { - flashlight.setOnClickListener(v -> { - cameraScanner.toggleIllumination(); - toggleTorch(); - }); - } else { - flashlight.setOnClickListener(v -> { - for (final Scanner s : scannerService.getConnectedScanners()) { - if (s.getIlluminationSupport() != null) - s.getIlluminationSupport().toggleIllumination(); - } - toggleTorch(); - }); - } + flashlight.setOnClickListener(v -> { + for (final Scanner s : scannerService.getConnectedScanners()) { + if (s.getIlluminationSupport() != null) + s.getIlluminationSupport().toggleIllumination(); + } + toggleTorch(); + }); } private void toggleTorch() { @@ -521,13 +393,13 @@ private void toggleTorch() { return; } - if (!anyScannerSupportsIllumination() && cameraScanner == null) { + if (!anyScannerSupportsIllumination()) { flashlight.setVisibility(View.GONE); } else { flashlight.setVisibility(View.VISIBLE); } - boolean isOn = anyScannerHasIlluminationOn() || (cameraScanner != null && cameraScanner.isIlluminationOn()); + boolean isOn = anyScannerHasIlluminationOn(); int iconId = isOn ? R.drawable.icn_flash_off_on : R.drawable.icn_flash_off; final int newColor = getResources().getColor(R.color.flashButtonColor); @@ -598,40 +470,10 @@ public void dismiss() { */ private void displayCameraButton() { if (findViewById(cameraToggleId) != null) { - findViewById(cameraToggleId).setOnClickListener(view -> initCamera()); + findViewById(cameraToggleId).setOnClickListener(view -> startCameraActivity()); } } - private void displayCameraReaderToggle() { - final Switch toggle = findViewById(scannerModeToggleViewId); - if (toggle == null) { - return; - } - - toggle.setOnCheckedChangeListener((buttonView, isChecked) -> { - Log.i(LOG_TAG, "Changing reader mode"); - CameraBarcodeScanView cameraView = findViewById(cameraViewId); - cameraView.setReaderMode(isChecked ? CameraReader.ZXING : CameraReader.ZBAR); - }); - } - - private void displayCameraPauseToggle() { - final Switch toggle = findViewById(scannerModeTogglePauseId); - if (toggle == null) { - return; - } - - toggle.setOnCheckedChangeListener((buttonView, isChecked) -> { - Log.i(LOG_TAG, "Toggling camera pause"); - CameraBarcodeScanView cameraView = findViewById(cameraViewId); - if (isChecked) { - cameraView.pauseCamera(); - } else { - cameraView.resumeCamera(); - } - }); - } - private boolean ledToggle = false; private void displayToggleLedButton() { diff --git a/enioka_scan_camera/.gitignore b/enioka_scan_camera/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/enioka_scan_camera/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/enioka_scan_camera/build.gradle b/enioka_scan_camera/build.gradle new file mode 100644 index 00000000..bb26b584 --- /dev/null +++ b/enioka_scan_camera/build.gradle @@ -0,0 +1,50 @@ +apply plugin: 'scanner.published-library' + +description('A library that makes the integration of all barcode scanners easy in any Android application, avoiding vendor lock-in and lowering the cost of advanced scanner integration.') + +android { + compileSdk 34 + defaultConfig { + minSdkVersion 19 + targetSdkVersion 28 + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lint { + disable 'ExpiredTargetSdkVersion' + } + namespace 'com.enioka.scanner.sdk.camera' +} + +ext { + mavenArtifactId = "provider-cs-camera" +} + + +dependencies { + //noinspection GradleCompatible + implementation project(':enioka_scan') + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.android.support.constraint:constraint-layout:2.0.4' + + // ZBAR & ZXING (Zebra Crossing) = camera. From Maven Central. + api('me.dm7.barcodescanner:zbar:1.9.8') { + transitive = false + } + api('me.dm7.barcodescanner:core:1.9.8') { + transitive = false + } + api 'com.google.zxing:core:3.5.1' + + // Test things (useless for now) + androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + androidTestImplementation project(path: ':enioka_scan_mock') + testImplementation 'junit:junit:4.13.2' +} diff --git a/enioka_scan_camera/src/main/AndroidManifest.xml b/enioka_scan_camera/src/main/AndroidManifest.xml new file mode 100644 index 00000000..e4c70955 --- /dev/null +++ b/enioka_scan_camera/src/main/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraApiLevel.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraApiLevel.java similarity index 57% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/CameraApiLevel.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraApiLevel.java index 874be8be..31886647 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraApiLevel.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraApiLevel.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; public enum CameraApiLevel { Camera1, Camera2 diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanView.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanView.java similarity index 99% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanView.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanView.java index ba8e6720..aa86f5be 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanView.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanView.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.content.Context; import android.content.res.TypedArray; @@ -6,13 +6,13 @@ import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; import android.os.Build; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.widget.FrameLayout; -import com.enioka.scanner.R; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.enioka.scanner.data.BarcodeType; /** diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewBase.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewBase.java similarity index 98% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewBase.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewBase.java index 892c60ce..c68871fa 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewBase.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewBase.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.app.Activity; import android.content.Context; @@ -8,8 +8,6 @@ import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -19,11 +17,12 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; -import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; -import com.enioka.scanner.R; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.enioka.scanner.data.BarcodeType; import java.util.ArrayList; @@ -231,7 +230,7 @@ protected void initLayout() { // The view holding the preview. This will in turn (camHolder.addCallback) call setUpCamera. if (this.camPreviewSurfaceView == null) { camPreviewSurfaceView = new CameraPreviewSurfaceView(getContext(), styledAttributes, this); - FrameLayout.LayoutParams prms = this.generateDefaultLayoutParams(); + LayoutParams prms = this.generateDefaultLayoutParams(); prms.gravity = Gravity.CENTER; camPreviewSurfaceView.setLayoutParams(prms); this.addView(camPreviewSurfaceView); @@ -309,7 +308,7 @@ protected void addTargetView() { final TargetView targetView = new TargetView(this.getContext(), this.styledAttributes); targetView.setId(R.id.barcode_scanner_camera_view); - final FrameLayout.LayoutParams prms = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int) rectHeightPixelsViewCoordinates); + final LayoutParams prms = new LayoutParams(LayoutParams.MATCH_PARENT, (int) rectHeightPixelsViewCoordinates); prms.setMargins(0, cropRect.top, 0, 0); Log.i(TAG, "Targeting overlay added"); @@ -360,7 +359,7 @@ public void resetTargetPosition() { computeCropRectangle(); allowTargetDrag = saveAllowTargetDrag; - final FrameLayout.LayoutParams prms = (LayoutParams) targetView.getLayoutParams(); + final LayoutParams prms = (LayoutParams) targetView.getLayoutParams(); prms.topMargin = cropRect.top; targetView.setLayoutParams(prms); } diff --git a/enioka_scan/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewScanner.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewScanner.java similarity index 98% rename from enioka_scan/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewScanner.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewScanner.java index 633b5476..3b7aab5e 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewScanner.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewScanner.java @@ -10,7 +10,7 @@ import com.enioka.scanner.api.proxies.ScannerDataCallbackProxy; import com.enioka.scanner.api.proxies.ScannerInitCallbackProxy; import com.enioka.scanner.api.proxies.ScannerStatusCallbackProxy; -import com.enioka.scanner.camera.CameraBarcodeScanView; +import com.enioka.scanner.sdk.camera.CameraBarcodeScanView; import com.enioka.scanner.data.Barcode; import com.enioka.scanner.data.BarcodeType; import com.enioka.scanner.helpers.Common; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewV1.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewV1.java similarity index 99% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewV1.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewV1.java index 826e545e..2cfe1564 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewV1.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewV1.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import static com.enioka.scanner.helpers.Permissions.PERMISSIONS_CAMERA; import static com.enioka.scanner.helpers.Permissions.hasPermissionSet; @@ -11,12 +11,11 @@ import android.graphics.Rect; import android.graphics.YuvImage; import android.hardware.Camera; -import androidx.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; -import com.enioka.scanner.R; +import androidx.annotation.NonNull; import java.io.ByteArrayOutputStream; import java.util.ArrayList; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewV2.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewV2.java similarity index 99% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewV2.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewV2.java index 8db7965d..dbd86620 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraBarcodeScanViewV2.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraBarcodeScanViewV2.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import static com.enioka.scanner.helpers.Permissions.PERMISSIONS_CAMERA; import static com.enioka.scanner.helpers.Permissions.hasPermissionSet; @@ -23,9 +23,6 @@ import android.os.Build; import android.os.Handler; import android.os.HandlerThread; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import android.util.AttributeSet; import android.util.Log; import android.util.Range; @@ -33,6 +30,10 @@ import android.view.SurfaceHolder; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -383,7 +384,7 @@ private void openCamera() { } acquire(); - CameraManager manager = (CameraManager) getContext().getSystemService(android.content.Context.CAMERA_SERVICE); + CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE); if (manager == null) { throw new RuntimeException("cannot use Camera2 API on this device - null CameraManager"); } diff --git a/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraCompatActivity.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraCompatActivity.java new file mode 100644 index 00000000..09ec69da --- /dev/null +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraCompatActivity.java @@ -0,0 +1,369 @@ +package com.enioka.scanner.sdk.camera; + +import static com.enioka.scanner.helpers.Permissions.PERMISSIONS_CAMERA; +import static com.enioka.scanner.helpers.Permissions.hasPermissionSet; +import static com.enioka.scanner.helpers.Permissions.requestPermissionSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; + +import android.annotation.SuppressLint; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.ImageButton; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + +import com.enioka.scanner.activities.ManualInputFragment; +import com.enioka.scanner.activities.ManualInputItem; +import com.enioka.scanner.api.Scanner; +import com.enioka.scanner.api.proxies.ScannerDataCallbackProxy; +import com.enioka.scanner.api.proxies.ScannerStatusCallbackProxy; +import com.enioka.scanner.data.Barcode; +import com.enioka.scanner.data.BarcodeType; +import com.enioka.scanner.helpers.Common; +import com.enioka.scanner.sdk.camera.R; +import com.enioka.scanner.service.ScannerClient; +import com.enioka.scanner.service.ScannerServiceApi; +import com.enioka.scanner.api.callbacks.ScannerStatusCallback; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * A camera helper activity that implements the camera scanner.

Basic usage is trivial : just inherit this class, and that's all.
+ * The activity will display a camera view, and will scan barcodes. The barcode data will be displayed in a text view with the ID {@code R.id.scanner_text_last_scan}.
+ * You may want to override the {@link #onData(List)} to get barcode data, and the {@link #onStatusChanged(Scanner, ScannerStatusCallback.Status)} to display scanner status from the camera scanner.
+ * It is also useful to change {@link #layoutIdCamera} to use a custom layout. + * By default, a basic test layout is provided.
+ * Also, {@link #cameraViewId} points to the camera view inside your camera layout. + */ +public class CameraCompatActivity extends AppCompatActivity implements ScannerClient { + protected final static String LOG_TAG = "CameraActivity"; + + protected final static int PERMISSION_REQUEST_ID_CAMERA = 1790; + + /** + * The layout to use when using camera scanner. + */ + protected int layoutIdCamera = R.layout.activity_main_alt; + + /** + * Optional camera scanner + */ + protected CameraBarcodeScanViewScanner cameraScanner; + + /** + * The ID of the optional ImageButton on which to press to toggle the flashlight/illumination. + */ + protected int flashlightViewId = R.id.scanner_flashlight; + + /** + * The ID of the {@link CameraBarcodeScanView} inside the {@link #layoutIdCamera} layout. + */ + protected int cameraViewId = R.id.camera_scan_view; + + /** + * The ID of the optional ImageButton on which to press to toggle the zxing/zbar camera scan library. + */ + protected int scannerModeToggleViewId = R.id.scanner_switch_zxing; + + protected int scannerModeTogglePauseId = R.id.scanner_switch_pause; + + protected int keyboardOpenViewId = R.id.scanner_bt_keyboard; + + /** + * An optional fragment allowing to input a value with the soft keyboard (for cases when scanners do not work). + */ + protected ManualInputFragment manualInputFragment; + + /** + * Auto completion items for manual input (with manualInputFragment). + */ + protected List autocompletionItems = new ArrayList<>(); + + /** + * How many characters should be entered before auto-completion starts. + */ + protected int threshold = 5; + + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Activity lifecycle callbacks + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.d(LOG_TAG, "Camera activity is created " + this.hashCode()); + + if (hasPermissionSet(this, PERMISSIONS_CAMERA)) { + setContentView(layoutIdCamera); + } else { + requestPermissionSet(this, PERMISSIONS_CAMERA, PERMISSION_REQUEST_ID_CAMERA); + } + } + + @Override + protected void onStart() { + super.onStart(); + Log.d(LOG_TAG, "Camera activity is starting " + this.hashCode()); + } + + @Override + protected void onResume() { + super.onResume(); + Log.i(LOG_TAG, "Camera activity is resuming " + this.hashCode()); + initCamera(); + } + + @Override + protected void onPause() { + Log.i(LOG_TAG, "Camera activity is being paused " + this.hashCode()); + if (cameraScanner != null) { + cameraScanner.disconnect(); + cameraScanner = null; + } + super.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + Log.i(LOG_TAG, "Camera activity is being stopped " + this.hashCode()); + } + + @Override + protected void onDestroy() { + Log.i(LOG_TAG, "Camera activity is being destroyed " + this.hashCode()); + super.onDestroy(); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Camera + //////////////////////////////////////////////////////////////////////////////////////////////// + + protected void initCamera() { + Log.i(LOG_TAG, "Giving up on laser, going to camera"); + if (!Common.hasCamera(this)) { + Log.i(LOG_TAG, "No camera available on device"); + Toast.makeText(this, R.string.scanner_status_no_camera, Toast.LENGTH_SHORT).show(); + + // Is it the right way to finish an activity? + finish(); + + return; + } + + if (hasPermissionSet(this, PERMISSIONS_CAMERA)) { + // The view needs permissions BEFORE initializing. And it initializes as soon as the layout is set. + setContentView(layoutIdCamera); + initCameraScanner(); + + // Reinit text + if (findViewById(R.id.scanner_text_scanner_status) != null) { + TextView tv = findViewById(R.id.scanner_text_scanner_status); + tv.setText(""); + } + } else { + requestPermissionSet(this, PERMISSIONS_CAMERA, PERMISSION_REQUEST_ID_CAMERA); + } + } + + private void initCameraScanner() { + if (cameraScanner != null) { + return; + } + // TODO: should be in camera constructor, not here... + CameraBarcodeScanView cameraView = findViewById(cameraViewId); + if (cameraView == null) { + Toast.makeText(this, R.string.scanner_status_no_camera, Toast.LENGTH_SHORT).show(); + return; + } + + final Set symbologies = new HashSet<>(); + if (getIntent().getExtras() != null && getIntent().getExtras().getStringArray(ScannerServiceApi.EXTRA_SYMBOLOGY_SELECTION) != null) { + for (final String symbology : Objects.requireNonNull(getIntent().getExtras().getStringArray(ScannerServiceApi.EXTRA_SYMBOLOGY_SELECTION))) { + symbologies.add(BarcodeType.valueOf(symbology)); + } + } + if (symbologies.isEmpty()) { + symbologies.add(BarcodeType.CODE128); + } + cameraScanner = new CameraBarcodeScanViewScanner(cameraView, new ScannerDataCallbackProxy((s, data) -> CameraCompatActivity.this.onData(data)), new ScannerStatusCallbackProxy(this), symbologies); + + if (findViewById(R.id.scanner_text_last_scan) != null) { + ((TextView) findViewById(R.id.scanner_text_last_scan)).setText(null); + } + displayTorch(); + displayManualInputButton(); + displayCameraReaderToggle(); + displayCameraPauseToggle(); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Permissions + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == PERMISSION_REQUEST_ID_CAMERA) { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + //goToCamera = true; // in case the activity was paused by the permission request dialog + setContentView(layoutIdCamera); + initCameraScanner(); + } else { + Toast.makeText(this, R.string.scanner_status_no_camera, Toast.LENGTH_SHORT).show(); + } + } + } + + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Scanner lifecycle callbacks + //////////////////////////////////////////////////////////////////////////////////////////////// + + @SuppressLint("SetTextI18n") // Text is already localized, only special characters remain. + @Override + public void onStatusChanged(final Scanner scanner, final ScannerStatusCallback.Status newStatus) { + if (findViewById(R.id.scanner_text_scanner_status) != null) { + TextView tv = findViewById(R.id.scanner_text_scanner_status); + tv.setText((scanner == null ? "" : (scanner.getProviderKey() + ": ")) + newStatus + " --- " + newStatus.getLocalizedMessage(this) + "\n" + tv.getText()); + } + } + @Override + public void onScannerInitEnded(int count) { + // Do nothing + } + @Override + public void onProviderDiscoveryEnded() { + // Do nothing + } + + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Scanner data callback + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onData(List data) { + StringBuilder res = new StringBuilder(); + for (Barcode b : data) { + Log.d(LOG_TAG, "Received barcode from scanner: " + b.getBarcode() + " - " + b.getBarcodeType().code); + res.append(b.getBarcode()).append("\n").append(b.getBarcodeType().code).append("\n"); + } + if (findViewById(R.id.scanner_text_last_scan) != null) { + ((TextView) findViewById(R.id.scanner_text_last_scan)).setText(res.toString()); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Button and input initialization + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Display a manual input (keyboard) button for manual input. + */ + private void displayManualInputButton() { + final View bt = findViewById(keyboardOpenViewId); + if (bt == null) { + return; + } + + bt.setOnClickListener(view -> { + manualInputFragment = ManualInputFragment.newInstance(); + manualInputFragment.setAutocompletionItems(autocompletionItems, threshold); + manualInputFragment.setDialogInterface(new DialogInterface() { + @Override + public void cancel() { + + } + + @Override + public void dismiss() { + + } + }); + manualInputFragment.show(getSupportFragmentManager(), "manual"); + }); + } + + /** + * Display the torch button "on" or "off" is the device has capability. + **/ + private void displayTorch() { + final ImageButton flashlight = findViewById(flashlightViewId); + if (findViewById(flashlightViewId) == null) { + return; + } + + toggleTorch(); + + if (cameraScanner != null) { + flashlight.setOnClickListener(v -> { + cameraScanner.toggleIllumination(); + toggleTorch(); + }); + } + } + + private void toggleTorch() { + final ImageButton flashlight = findViewById(flashlightViewId); + if (findViewById(flashlightViewId) == null) { + return; + } + + flashlight.setVisibility(View.VISIBLE); + + boolean isOn = cameraScanner != null && cameraScanner.isIlluminationOn(); + int iconId = isOn ? R.drawable.icn_flash_off_on : R.drawable.icn_flash_off; + + final int newColor = getResources().getColor(R.color.flashButtonColor); + flashlight.setColorFilter(newColor, PorterDuff.Mode.SRC_ATOP); + flashlight.setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), iconId)); + } + + private void displayCameraReaderToggle() { + final Switch toggle = findViewById(scannerModeToggleViewId); + if (toggle == null) { + return; + } + + toggle.setOnCheckedChangeListener((buttonView, isChecked) -> { + Log.i(LOG_TAG, "Changing reader mode"); + CameraBarcodeScanView cameraView = findViewById(cameraViewId); + cameraView.setReaderMode(isChecked ? CameraReader.ZXING : CameraReader.ZBAR); + }); + } + + private void displayCameraPauseToggle() { + final Switch toggle = findViewById(scannerModeTogglePauseId); + if (toggle == null) { + return; + } + + toggle.setOnCheckedChangeListener((buttonView, isChecked) -> { + Log.i(LOG_TAG, "Toggling camera pause"); + CameraBarcodeScanView cameraView = findViewById(cameraViewId); + if (isChecked) { + cameraView.pauseCamera(); + } else { + cameraView.resumeCamera(); + } + }); + } +} diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraPreviewSurfaceView.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraPreviewSurfaceView.java similarity index 97% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/CameraPreviewSurfaceView.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraPreviewSurfaceView.java index 749e0d11..35998183 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraPreviewSurfaceView.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraPreviewSurfaceView.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.content.Context; import android.content.res.TypedArray; @@ -6,8 +6,6 @@ import android.view.SurfaceHolder; import android.view.SurfaceView; -import com.enioka.scanner.R; - /** * A helper view for displaying the camera preview. It should not be needed in case we want the preview * to be stretched to the whole available surface, but with Camera V2 (and only V2) some dark magic diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraReader.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraReader.java similarity index 88% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/CameraReader.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraReader.java index 50320c56..c63c638b 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/CameraReader.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CameraReader.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; /** * The different barcode reading libraries available. diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/CroppedPicture.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CroppedPicture.java similarity index 84% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/CroppedPicture.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CroppedPicture.java index 020816f6..a29e90d9 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/CroppedPicture.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/CroppedPicture.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; /** * Data that must be analysed by a {@link FrameAnalyser}. It must be already cropped and rotated. diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalyser.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalyser.java similarity index 95% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalyser.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalyser.java index efffcd2a..d9aff173 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalyser.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalyser.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.os.Process; import android.util.Log; @@ -26,7 +26,7 @@ protected FrameAnalyser(FrameAnalyserManager parent) { @Override public void run() { - android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); initScanner(); FrameAnalysisContext ctx = null; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalyserManager.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalyserManager.java similarity index 99% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalyserManager.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalyserManager.java index 37b27749..0bd17570 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalyserManager.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalyserManager.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.graphics.Point; import android.util.Log; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalysisContext.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalysisContext.java similarity index 89% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalysisContext.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalysisContext.java index f2b774aa..1f3e7e2f 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/FrameAnalysisContext.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/FrameAnalysisContext.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; /** * All the data needed for a frame analysis. diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/Resolution.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/Resolution.java similarity index 99% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/Resolution.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/Resolution.java index 36127190..5526347d 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/Resolution.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/Resolution.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.content.Context; import android.graphics.Point; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/ScannerCallback.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ScannerCallback.java similarity index 96% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/ScannerCallback.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ScannerCallback.java index e20d13ae..5b417271 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/ScannerCallback.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ScannerCallback.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.graphics.Point; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/TargetView.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/TargetView.java similarity index 97% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/TargetView.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/TargetView.java index 8466eb7e..30a4428f 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/TargetView.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/TargetView.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.content.Context; import android.content.res.TypedArray; @@ -7,13 +7,11 @@ import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.Rect; -import androidx.annotation.ColorInt; -import androidx.annotation.Nullable; -import android.util.AttributeSet; import android.util.Log; import android.view.View; -import com.enioka.scanner.R; +import androidx.annotation.ColorInt; +import androidx.annotation.Nullable; /** * The "target visor" view to be drawn on top of the scanner view. diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/ViewHelpersPreferences.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ViewHelpersPreferences.java similarity index 98% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/ViewHelpersPreferences.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ViewHelpersPreferences.java index 88294cbc..e93d9df7 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/ViewHelpersPreferences.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ViewHelpersPreferences.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.app.Activity; import android.content.Context; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/ViewHelpersResolution.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ViewHelpersResolution.java similarity index 99% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/ViewHelpersResolution.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ViewHelpersResolution.java index 9e1dc512..01740d91 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/ViewHelpersResolution.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ViewHelpersResolution.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.app.ActivityManager; import android.content.Context; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/ZBarFrameAnalyser.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZBarFrameAnalyser.java similarity index 99% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/ZBarFrameAnalyser.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZBarFrameAnalyser.java index 457f0ab2..33dae48e 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/ZBarFrameAnalyser.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZBarFrameAnalyser.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.text.TextUtils; import android.util.Log; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/ZBarScanView.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZBarScanView.java similarity index 91% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/ZBarScanView.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZBarScanView.java index 80f871dc..7c46c54a 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/ZBarScanView.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZBarScanView.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.content.Context; import android.util.AttributeSet; diff --git a/enioka_scan/src/main/java/com/enioka/scanner/camera/ZXingFrameAnalyser.java b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZXingFrameAnalyser.java similarity index 99% rename from enioka_scan/src/main/java/com/enioka/scanner/camera/ZXingFrameAnalyser.java rename to enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZXingFrameAnalyser.java index 11615266..e96b7971 100644 --- a/enioka_scan/src/main/java/com/enioka/scanner/camera/ZXingFrameAnalyser.java +++ b/enioka_scan_camera/src/main/java/com/enioka/scanner/sdk/camera/ZXingFrameAnalyser.java @@ -1,4 +1,4 @@ -package com.enioka.scanner.camera; +package com.enioka.scanner.sdk.camera; import android.util.Log; diff --git a/enioka_scan_camera/src/main/res/drawable-hdpi/icn_flash_off.png b/enioka_scan_camera/src/main/res/drawable-hdpi/icn_flash_off.png new file mode 100644 index 0000000000000000000000000000000000000000..5deb311c40e4903a06b0aa006a6a4d8089c40399 GIT binary patch literal 2381 zcmV-T39|NyP)Px;2T4RhRCodHoLNj2Nfd^GVR1mg5d;Q?AVY=#f}*JNVqBsbLySJSL`^hm-1p_d zM`Mge6JLDL2X_;FaEY4eizXTw9VcoKHK1f>a04VDpe(X0&iPxqt?t|1xBK2+%6mD< zvFmnMSDpSi_tdHCx`u{0Bcaqy6zL$+$bOBWV;G}Uv`zY`Wl?*n+|#dJbnGVmLTal3 zfL-zfH9UkghBTTKP7eQ)`;^zQ6%2=}QjfMME zyB`)I1Ay6n9zTBkZ29u#&)9Qn<@oscutSFqjS3GBXYE$2DxAA;;lj&{7cb&%iCglP zIu@qrtigZ`*tUxr>?cp2JYTkKS-D>4@cuDl#u)krR99EOnKf(H1HJYfxCY38EiH8- zR%1oV5m~Wf#q&px9?75<6cps1K7Cr|>8vrcXU`r&b#mBqTIJ^E=B8DvR+VU7ckn!z z3ge&{qcI4w-fg=rTCmTYIim`D^XAQkp`oFoy_)uQb#-;pfP1g5uFj`7A({>Qb^%O< z#W>M$$Gn-fR}D7h*ttsB`}gl3k&uv}IuT&o`%H59@Zq};A3nr>4PHcG3(%mBeHX5X z7HotH7=+0UWhZ>xXA#WQ?Gq zt{}r$xpHNNZY6gw4no*K?6Yk)X!iML%$N~#jY;>yZO;U2Ae9Gve%=)kT{ zu4LxSnS;lU9jlu&Bf~g&@E~s)h8D*NfQE7<+qP{(&a7PUlG%9W%9Z=)&Yj~e!;sm? zdQ8 zP{CMforDD~K?wkw*XuQ3JXS*(Y_wF5SBxlw$ zw4Gmg3UVQY^ajBz^E? zJe=#9M^sc)NMvNB?lq_-Ms^;|mF3y;Psm+PRr zySqb35yn(y!h{Kfva_=@)h=SvvTohFI~5fbyynxNF%a_T0UkVQ=`&X?<)ay4BTe50 z$jQmcu7^Mm!@r*B`7S_DnlvdoGc(g8em6EYzN1%QcQBho#&Z7r`Kih!R*eUD`tu-a+QNFS+ZnkYHI2)fcTPxJXsgAH`vFIAJ<)W74NtB2&P~wTTsFe7P%4fPQjaL zQNNNrxdam$qoU^7?BQ@BxsdAKqu)$ISEsf^=1}4!_N|QvRoj%^Yd2F{rU&9?U|@wOLe6e#%$<78wlR-QE*FWyFs6kouy{% zQ-+bAo}SKIw{GDF^mYjt%90CZ=s?GSpFxV1y?_#gk*ut&5qtLRDHb>A*zkb(Vg4&p z$(zxK8fcs!Oqz;9pb6GRY+kc|OU$rcS0-AZQHhIzQD!awA7ld{Ypyazv)3BvgYo2* zy)!t=U@hr7)7zM8=gG?n;}-RTYX`eg92wmOqR|3y!CGuG}=R4 z!eTbQI>PTW=ok!w=WZm$)Lk~~GxG5M4sP&jOl$x=kOkutR^oIs3q1h-f)?AxAelfK zXyF84;l+Nx>az+o*&?KV7$~uwmWv-C!6+XEgB(`iux5df;kQ@`nl%Q4CH`|2$My z_bL=+G>UDzKM00000NkvXXu0mjfEFX;~ literal 0 HcmV?d00001 diff --git a/enioka_scan_camera/src/main/res/drawable-hdpi/icn_flash_off_on.png b/enioka_scan_camera/src/main/res/drawable-hdpi/icn_flash_off_on.png new file mode 100644 index 0000000000000000000000000000000000000000..16e8efbffcd060210b43fd1fa63fd81d75484706 GIT binary patch literal 2062 zcmV+p2=VucP)Px+$Vo&&RCodHoPB6jWf;KcYR=X^T>FS^;@pPe5X!-b421blL#Y)jVbUKt(o)w# z2FWV=BWz&(BO@3KWg9{w3L1<4Fv%E-3?ykqSYc+LX>03Bvc@12f$gPgou?Ogp?6cfCn8~LIL^-G305{l>%69#X|r-D0<(c)Z!n( zfF=g#il$raGg_-pis3_|%ZlO41&tTyi#{$IOR^|8+b?R_yYWh^@|0WvWL2{WtM_B2 zKKIN(Pt3Li+X`sBpIFR*7wbYs#jlyP(3F@34dgsgzRkG&Pk_l634p0I&PN#WvRjR4Gaql7=ud^@o=8L@^`zc$R6E>bXxu+O`1znRUBHrrPYCe_ ztxZZyw;HdgOMpxbmM-xI%~Iz|U4?VqbOb)Y5SA|S1|3i3Txf#+;K9;;z*F9vOG`_W zE?&IYkeHar^F~8CfByWLy1KeQ4J(GHg67rEDY|<`S;4PzZ3_tCx`N4ky2KU9zD825NbTnDDk zyjt_PE5(Y*zu9 zm8Zf;_H3oEp`oFsoSdB3jjp+Q^X9RQ8#jJsRL`dK|KQPpR#MKLJ6A4{tBs7445L$F z$e6zd&@5alCnY5%NjrD${8S9n25em$CByi6+qP{gWEi^kEfua-7W9P+7xpG6Czk}W zo($vAp+j{yZrotwqRQd~ZEBVk$-8K3YFb}hT)aO}pJW*A?d|)IA3x5vE!8E7pCw-7 zJ{7m!=*h{+wzRag7XujL=<4cvucD&jhX8d{I<*L3!iO@_-QE3)0ptXU%fDu3X6E$t z^wjt>yuZKy?v5QhuJ}72;qpYKKv!2+rT_2an|D=I#onzxnz3zZx1E_O!IL{2NR=A->juN3-MIx$qI<#w|5> z_Uzd*f&7N0i@Yiei@kw4@-kaXcW@cu7s;a7b=hCH1Gv4PE`g;6YdS$W{<)vNb)FI1;+0gq;vC_8MF70E_E^BySWLBJK6u+&|@ew}wr zRF{4{+Vo~>JMM<*xIli*z3+*Mi66Ia-THnMtZ`^&&uaPe1}RZ;KgaO!@E2KGSyh_F zV`F3AZ`rb?p|`h}_er8b_{H7EqY=DXInd3`%_Rc)Wv7Mm&*dLDW?(iv(xSTq5>Nz0y_4T!{Tet4>h#L@^4tdprm-n6G z4V6taY^JeQWZ}PEvWs5|3k#3gYDjRMFMbS5-z^9 z#emRt+AmGH25xOI)S4%F+q%Rk4_qI}z}KP~6s1QPdL$R#p@aJZevznq{H8oE<_Iv6 z`difH&0OZ~(Ueia6etWkx_I`6wi*s76@*_uby{Q44?3r0ZqH)gm^YjW8$y{f{5nHhLEXj7BqG7 zY#xB}=2oo7Y*^e8<(Fph5*&Y;k5I43s=Pi1w*FgB&Yxykbnq2wFl3+T9oiOa5~ea_{Ag1MY1_ z>a#Y`^He0{OAp}!t-+yvpcBJUJY5y=fW>o(zbJ4+;=R(2kAxevPlr+fXm+ond?qKy sj&RumJd{iUxTIyoUdx$-T(fNX55|+$c@kp!w*UYD07*qoM6N<$f_qB`4gdfE literal 0 HcmV?d00001 diff --git a/enioka_scan_camera/src/main/res/drawable-mdpi/icn_flash_off.png b/enioka_scan_camera/src/main/res/drawable-mdpi/icn_flash_off.png new file mode 100644 index 0000000000000000000000000000000000000000..d7d7a29d5101e201abbc8dd14c0cc5150313c0ea GIT binary patch literal 1574 zcmV+>2HE+EP)Px);7LS5RA>d|T1`k}R}@ZSQfm{_amESsC)Pzv$F{Z-W1$NfP{EE%7ozwB3Zl4D z5H~IaK~U7Kh=Ln;3NBmo5UzH&Y-d!3ev*?0bf%2`Kvm8B}dxi9@7};IWsW> znxvSd9%I1&rl4PyhK z*>v#P2p|#_V0nx9g7}*C^MG;e!14bp1Puc$0$GTJfKh&zIB8R!o}T_JCnqPcwY3$V z;NNLp>nGyTGvbhzg@Er~XVzpY0q7G`fxVZ55_4OS}^~q=hHe_Oc z7R6-y?bOs1(!0kU9UTv2fv&8qG&VIgm1?zGp>>6^%*@Pu7p^E<0LC*msf8*GeA3gv zcLRZdo6On@&^DVbPp8v8-PqXhFrnk)<6jw#M#&9cTU-07r>Dok#wz@csQnCp0Th50 zAs%#5QIVDT^uWMC9@QU6O|-YS=V)kX_*tq?p*G+Q0mg14Gf|8<(E62?l_!3`KiJ*f zU7C@RA+n^iv$NC2#>Q2z*Bd@B6FMn3{APD|SCj@u3{<8PM7Ty~B^fc5nM0##Z*R{fF5~5qzXyhfh8AaMXK_y6 z2EBkIi%d+(nX|LAwe|J&b}5;2b8|o3B3LXz4-J1v%%U|K6(u^0AC#1oe9jAXxm?c0 z#lAZ@mR63BkK?|Olag~oTS&wCG$`|ifk|~!gcdzlQBh%{^Y{^U zV6#KycDs)#`&v~QEavhdV8MLED?_(T^7(us39YTIpHgEO?9tJYi!{4>b#gsB9et!N3tj+0k9@f;~`w``_v9a>3tSpl-4Mn>O6iO|jVcc}6O0~7McdDwYY?uUjGii3s z2Nrlq}lCQ<2cX;fF_ea+1}oUcI47A33$l>!>m!xk}H*e zo^C+yQ$DSu*S}x*KB+nn+HSY!DF7PRJGicm$f2=|cvTFakr*JCD33Pw_Vzjwk;8+g zpyr*QpMRQ&48d3^(?uLQ=b47lj|PBM)R))S*TdI4m?U0epeb;BDF*x+?{gC4aFG~( z8R4~wLZ#6~=Br2BpgXwD@WNH~+-rfuj!JMqq=vqs%xSccI}?3Fe6y!Wcd(`@fd| Y0Auj^c>v8VdjJ3c07*qoM6N<$g5w$RH~;_u literal 0 HcmV?d00001 diff --git a/enioka_scan_camera/src/main/res/drawable-mdpi/icn_flash_off_on.png b/enioka_scan_camera/src/main/res/drawable-mdpi/icn_flash_off_on.png new file mode 100644 index 0000000000000000000000000000000000000000..65425e23cb278e156c7df7508564663571d0da99 GIT binary patch literal 1311 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 bA0hI8qmSxi3II~|00000NkvXXu0mjfgLolR literal 0 HcmV?d00001 diff --git a/enioka_scan_camera/src/main/res/drawable-xhdpi/icn_flash_off_on.png b/enioka_scan_camera/src/main/res/drawable-xhdpi/icn_flash_off_on.png new file mode 100644 index 0000000000000000000000000000000000000000..1dc83b55ae6aa99aa6d7439b502392500ca247e5 GIT binary patch literal 2729 zcmV;a3Rd-rP)00001b5ch_0Itp) z=>PxcdX>2&$~Rnfc{m9L)3gxp!_ z3;F(q=vbUi%HO^a4ClPsLZWm?f<%l>57_Xfp8uqi9p`ob;vLoK?#1Mra30^x()X5)=WS5hI4RIE_ zH#|Bc$rLb!SRneU}0LIP_j+Ez6TuFKY{!j=5ny#LFrO<|uFT)KapSM@ z^Yd9Ou_P~Eyy)DsXU}#^7kQg_3gB38W$G)CPaIslc=5+};7(3Xj+{AjrtZ+8Lu_f) zMPLZah{OVheBk8p;lmY+7A<<;PQ`BCy!p$js;bZIT45f!ov5^Xc;C z%XNiI)nOS~yH|jj&kU4QS69DYSy{Q$YNbX-Mw%ob`^D%ekM(LTk(tQA0^YxWe|=tF zUa=KK5;1q|+O_M$J9qAAPgm+4aasV={|3r~C2Ia=X=&+qtiUB=K7IQ1hewVa(J5k1 zRmI5L5`arvU6v}PPUocWoPPK2-HS3TvQnqX8#iuzv}VnkPj#xRiLySxg9A18y?ps{ ztwp%gh?oNi7ykKy0(|h`!NnpUnD}K!lSst;R~Zf+jUEWrmwcM&xuWcv*ItH(hEB?` z=uNW~dG_pC)7rIbe-MzM%Bb1{cyP*1TSiy;@!0L#x4&lv?)dn4$IhKQ>jDfHOw$3Z z{RD?hCl;?-wQ85yAD%?a&n056J9g|?m)UDHP4_BIbcJaAs*+aq>Fn%mm^EwGW|M`U zyng-qc4?Zgm`ty8vT?xT#oEe+3m4wB0C$=+&7YT*l~q1^^r+HIrDbMoaQ*uAAGfx) zT7GoXO#UvX$-{%c;qpyf%f6zbV*0&%_x>!yqH;HGGBGjHck<-P_iAct{^dsg*~n9C z@4b5U>IZJYm1)bK_M--@bj)(w5blO>ZTg!0kGE^k`LW zZS8-oT<62I6WRt@vQO%hnKNg;<+M?yk8VG3;6QbKef zhj%g!S$OW;xxb}bT_ON$XlQtM@7}#_9>8$pmSX^BBN{6Yft8k)mO7cjOu3_SY;3Gm zz`iR@|C0b2;yJ@4UYi$Kz?(O3eogjd)ue(Za9eil*ijvzr9xHRFYw?J(Nc9JXrB)s zKKy9m!i7IdRxjDP@!xIRwpB~S+?_0q#>b!H!8|1%NZGPw%Nq+8ET~FWIhn-x_tvdj zYfhay#k-q>D3Lz6Kx$SN#M-sBwbjp`Kfl_jZmcB99QJ$X&!0E-G83abG&uG^c`z@g zrnwG`NV7Xz9yj^EQH2EVKc#Pe|H_ps!$#)=atx*s52ij}7Y)?&z>gn4-aB{h+yubG z!^5{WZQ4|O?b@}3XK67+fP^1!8y<{27Yz*H-Me?s7r5_4Y8La);NajtHf-2Xck9-z zk(k3l{TlfJt7e&JSr!GQrm}qaYgu7>JGMUk{r%TuiSQ>)O-+FfDr4&_-ye#OC=VW$ zKX}~1^z4wN^`$UJEpWdZTe!ZyzQ3id(ya$&#jwQp=}Tq>)z$SU*$}Wt0xO0Kxg^9G_f>^s zJ(y!r@+yHYpC?Y7SfSu{bab4N8LZto2seRYyay9xm5auM_dRC`r2bG;RP?PUPoDfy zCOCfM`vSXDKsIl*h(_a$c#xdvb?4sh<$Ct)*;T-mjd366FkB1_yC_@^#CtHu@ZyRj z=Q!^>k*4?)>2vSMBPhS~UE#7SQ)No8#U3&M!ceSp86yF^tA;ZOX>KJ zIuazA2a}Ksg1+LCU=R%tuxexom%5|^%=vavE%!}R_#6<}M5ZK@)zv7-icL!fOwiL@ zhvGjAumhB(-lUQaFc&iQ#i~>E^>`c%#d8a=pb&lOXtL6n0nD}Z#cT*r%ZnTf#XAeI zVS&IZt(XN&Ms(&h)mE?hGO0hQ@KH~#jS046UW z^XLcpgyUo}f`h_1m!S|gwk??gRySq{MH9kUISjs(RqTBNlo_hDlNe^QcM34~0x-iU z9%c)~+w-Iz*%ln-bJ3L3k5&rhmbVdM&lU~)W^**?V|h&00000NkvXXu0mjf#CJY) literal 0 HcmV?d00001 diff --git a/enioka_scan_camera/src/main/res/drawable-xxhdpi/icn_flash_off.png b/enioka_scan_camera/src/main/res/drawable-xxhdpi/icn_flash_off.png new file mode 100644 index 0000000000000000000000000000000000000000..1c6930700cb7bbd3934af5ad3552b053cc7f4f2e GIT binary patch literal 4925 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 JPDHLkV1iFT9*Y0~ literal 0 HcmV?d00001 diff --git a/enioka_scan_camera/src/main/res/drawable-xxxhdpi/icn_flash_off_on.png b/enioka_scan_camera/src/main/res/drawable-xxxhdpi/icn_flash_off_on.png new file mode 100644 index 0000000000000000000000000000000000000000..8ba9be2bed76fc295df3db5fcd37bc4ffa90beda GIT binary patch literal 5871 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 FV1o3A;-dfn literal 0 HcmV?d00001 diff --git a/enioka_scan_camera/src/main/res/layout/activity_main_alt.xml b/enioka_scan_camera/src/main/res/layout/activity_main_alt.xml new file mode 100644 index 00000000..8d336a8d --- /dev/null +++ b/enioka_scan_camera/src/main/res/layout/activity_main_alt.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + diff --git a/enioka_scan_camera/src/main/res/layout/dropdown_item.xml b/enioka_scan_camera/src/main/res/layout/dropdown_item.xml new file mode 100644 index 00000000..d20f0145 --- /dev/null +++ b/enioka_scan_camera/src/main/res/layout/dropdown_item.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/enioka_scan_camera/src/main/res/layout/fragment_scan_manual_input.xml b/enioka_scan_camera/src/main/res/layout/fragment_scan_manual_input.xml new file mode 100644 index 00000000..027d330c --- /dev/null +++ b/enioka_scan_camera/src/main/res/layout/fragment_scan_manual_input.xml @@ -0,0 +1,56 @@ + + + + + + + + + +