From 1917198305bcfc05dda0a6b8126b6faf06e527f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Fri, 20 Jan 2023 16:43:28 +0100 Subject: [PATCH] Move optional appscan feature to a separate module to avoid duplicating code between variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This now uses a AppScanOptionalFeature injected interface that is satisfied by each module, reducing the duplicated code to a minimum Signed-off-by: Álvaro Brey --- app/build.gradle | 8 +- .../com/nextcloud/client/di/VariantModule.kt | 34 ++++++++ .../android/ui/activity/AppScanActivity.kt | 42 ---------- .../com/nextcloud/client/di/VariantModule.kt | 37 +++++++++ .../android/ui/activity/AppScanActivity.kt | 80 ------------------- .../com/nextcloud/client/di/VariantModule.kt | 37 +++++++++ .../android/ui/activity/AppScanActivity.kt | 77 ------------------ .../com/nextcloud/client/di/AppComponent.java | 1 + .../documentscan/AppScanOptionalFeature.kt | 45 +++++++++++ .../documentscan/DocumentScanActivity.kt | 17 ++-- .../ui/activity/FileDisplayActivity.java | 40 ---------- .../ui/activity/UploadFilesActivity.java | 3 +- .../fragment/OCFileListBottomSheetDialog.java | 12 ++- .../OCFileListBottomSheetDialogFragment.kt | 7 +- .../ui/fragment/OCFileListFragment.java | 1 - .../owncloud/android/utils/PermissionUtil.kt | 1 - .../com/nextcloud/client/di/VariantModule.kt | 37 +++++++++ .../android/ui/activity/AppScanActivity.kt | 77 ------------------ .../com/nextcloud/client/di/VariantModule.kt | 34 ++++++++ .../android/ui/activity/AppScanActivity.kt | 41 ---------- appscan/.gitignore | 1 + appscan/build.gradle | 41 ++++++++++ appscan/consumer-rules.pro | 0 appscan/proguard-rules.pro | 21 +++++ appscan/src/main/AndroidManifest.xml | 29 +++++++ .../com/nextcloud/appscan/AppScanActivity.kt | 67 ++++++++++++++++ .../nextcloud/appscan}/ScanPageContract.kt | 3 +- build.gradle | 2 + settings.gradle | 1 + 29 files changed, 417 insertions(+), 379 deletions(-) create mode 100644 app/src/generic/java/com/nextcloud/client/di/VariantModule.kt delete mode 100644 app/src/generic/java/com/owncloud/android/ui/activity/AppScanActivity.kt create mode 100644 app/src/gplay/java/com/nextcloud/client/di/VariantModule.kt delete mode 100644 app/src/gplay/java/com/owncloud/android/ui/activity/AppScanActivity.kt create mode 100644 app/src/huawei/java/com/nextcloud/client/di/VariantModule.kt delete mode 100644 app/src/huawei/java/com/owncloud/android/ui/activity/AppScanActivity.kt create mode 100644 app/src/main/java/com/nextcloud/client/documentscan/AppScanOptionalFeature.kt create mode 100644 app/src/qa/java/com/nextcloud/client/di/VariantModule.kt delete mode 100644 app/src/qa/java/com/owncloud/android/ui/activity/AppScanActivity.kt create mode 100644 app/src/versionDev/java/com/nextcloud/client/di/VariantModule.kt delete mode 100644 app/src/versionDev/java/com/owncloud/android/ui/activity/AppScanActivity.kt create mode 100644 appscan/.gitignore create mode 100644 appscan/build.gradle create mode 100644 appscan/consumer-rules.pro create mode 100644 appscan/proguard-rules.pro create mode 100644 appscan/src/main/AndroidManifest.xml create mode 100644 appscan/src/main/java/com/nextcloud/appscan/AppScanActivity.kt rename {app/src/main/java/com/nextcloud/client/documentscan => appscan/src/main/java/com/nextcloud/appscan}/ScanPageContract.kt (93%) diff --git a/app/build.gradle b/app/build.gradle index 1f86e5a309..95a66867a0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -244,7 +244,7 @@ dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.google.android.material:material:1.8.0' implementation 'com.jakewharton:disklrucache:2.0.2' - implementation 'androidx.appcompat:appcompat:1.6.0' + implementation "androidx.appcompat:appcompat:$appCompatVersion" implementation 'androidx.webkit:webkit:1.5.0' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.exifinterface:exifinterface:1.3.5' @@ -276,9 +276,9 @@ dependencies { implementation "com.github.nextcloud-deps.hwsecurity:hwsecurity-fido2:$fidoVersion" // document scanner not available on FDroid (generic) due to OpenCV binaries - gplayImplementation "com.github.zynkware:Document-Scanning-Android-SDK:$documentScannerVersion" - huaweiImplementation "com.github.zynkware:Document-Scanning-Android-SDK:$documentScannerVersion" - qaImplementation "com.github.zynkware:Document-Scanning-Android-SDK:$documentScannerVersion" + gplayImplementation project(':appscan') + huaweiImplementation project(':appscan') + qaImplementation project(':appscan') spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.12.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.4.7' diff --git a/app/src/generic/java/com/nextcloud/client/di/VariantModule.kt b/app/src/generic/java/com/nextcloud/client/di/VariantModule.kt new file mode 100644 index 0000000000..d9d2703668 --- /dev/null +++ b/app/src/generic/java/com/nextcloud/client/di/VariantModule.kt @@ -0,0 +1,34 @@ +/* + * Nextcloud Android client application + * + * @author Chris Narkiewicz + * Copyright (C) 2919 Chris Narkiewicz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + */ +package com.nextcloud.client.di + +import com.nextcloud.client.documentscan.AppScanOptionalFeature +import dagger.Module +import dagger.Provides +import dagger.Reusable + +@Module +internal class VariantModule { + @Provides + @Reusable + fun scanOptionalFeature(): AppScanOptionalFeature { + return AppScanOptionalFeature.Stub + } +} diff --git a/app/src/generic/java/com/owncloud/android/ui/activity/AppScanActivity.kt b/app/src/generic/java/com/owncloud/android/ui/activity/AppScanActivity.kt deleted file mode 100644 index 632a8db524..0000000000 --- a/app/src/generic/java/com/owncloud/android/ui/activity/AppScanActivity.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * Copyright (C) 2022 Tobias Kaminsky - * Copyright (C) 2022 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.ui.activity - -import android.app.Activity -import com.owncloud.android.lib.common.utils.Log_OC - -class AppScanActivity { - // stub - companion object { - private val TAG = AppScanActivity::class.simpleName - - @JvmStatic - val enabled: Boolean = false - - @JvmStatic - fun scanFromCamera(activity: Activity, requestcode: Int) { - // stub - Log_OC.w(TAG, "scanFromCamera called in stub implementation") - } - } -} diff --git a/app/src/gplay/java/com/nextcloud/client/di/VariantModule.kt b/app/src/gplay/java/com/nextcloud/client/di/VariantModule.kt new file mode 100644 index 0000000000..c5767a91e0 --- /dev/null +++ b/app/src/gplay/java/com/nextcloud/client/di/VariantModule.kt @@ -0,0 +1,37 @@ +/* + * Nextcloud Android client application + * + * @author Chris Narkiewicz + * Copyright (C) 2919 Chris Narkiewicz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + */ +package com.nextcloud.client.di + +import com.nextcloud.appscan.ScanPageContract +import com.nextcloud.client.documentscan.AppScanOptionalFeature +import dagger.Module +import dagger.Provides +import dagger.Reusable + +@Module +internal class VariantModule { + @Provides + @Reusable + fun scanOptionalFeature(): AppScanOptionalFeature { + return object : AppScanOptionalFeature() { + override fun getScanContract() = ScanPageContract() + } + } +} diff --git a/app/src/gplay/java/com/owncloud/android/ui/activity/AppScanActivity.kt b/app/src/gplay/java/com/owncloud/android/ui/activity/AppScanActivity.kt deleted file mode 100644 index 92f125b948..0000000000 --- a/app/src/gplay/java/com/owncloud/android/ui/activity/AppScanActivity.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Álvaro Brey Vilas - * Copyright (C) 2022 Álvaro Brey Vilas - * Copyright (C) 2022 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.ui.activity - -import android.Manifest -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import com.owncloud.android.R -import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.PermissionUtil -import com.zynksoftware.documentscanner.ScanActivity -import com.zynksoftware.documentscanner.model.DocumentScannerErrorModel -import com.zynksoftware.documentscanner.model.ScannerResults -import com.zynksoftware.documentscanner.ui.DocumentScanner - -@Suppress("unused") -class AppScanActivity : ScanActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - addFragmentContentLayout() - } - - override fun onError(error: DocumentScannerErrorModel) { - DisplayUtils.showSnackMessage(this, R.string.error_starting_scan_doc) - } - - override fun onSuccess(scannerResults: ScannerResults) { - val intent = Intent() - - intent.putExtra( - EXTRA_FILE, - scannerResults.transformedImageFile?.absolutePath ?: scannerResults.croppedImageFile?.absolutePath - ) - - setResult(Activity.RESULT_OK, intent) - finish() - } - - override fun onClose() { - finish() - } - - companion object { - @JvmStatic - val enabled: Boolean = true - - const val EXTRA_FILE = "file" - - @JvmStatic - fun scanFromCamera(activity: Activity, requestCode: Int) { - DocumentScanner.init(activity) - val scanIntent = Intent(activity, AppScanActivity::class.java) - if (PermissionUtil.checkSelfPermission(activity, Manifest.permission.CAMERA)) { - activity.startActivityForResult(scanIntent, requestCode) - } else { - PermissionUtil.requestCameraPermission(activity, PermissionUtil.PERMISSIONS_SCAN_DOCUMENT) - } - } - } -} diff --git a/app/src/huawei/java/com/nextcloud/client/di/VariantModule.kt b/app/src/huawei/java/com/nextcloud/client/di/VariantModule.kt new file mode 100644 index 0000000000..c5767a91e0 --- /dev/null +++ b/app/src/huawei/java/com/nextcloud/client/di/VariantModule.kt @@ -0,0 +1,37 @@ +/* + * Nextcloud Android client application + * + * @author Chris Narkiewicz + * Copyright (C) 2919 Chris Narkiewicz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + */ +package com.nextcloud.client.di + +import com.nextcloud.appscan.ScanPageContract +import com.nextcloud.client.documentscan.AppScanOptionalFeature +import dagger.Module +import dagger.Provides +import dagger.Reusable + +@Module +internal class VariantModule { + @Provides + @Reusable + fun scanOptionalFeature(): AppScanOptionalFeature { + return object : AppScanOptionalFeature() { + override fun getScanContract() = ScanPageContract() + } + } +} diff --git a/app/src/huawei/java/com/owncloud/android/ui/activity/AppScanActivity.kt b/app/src/huawei/java/com/owncloud/android/ui/activity/AppScanActivity.kt deleted file mode 100644 index 1d1d1bdb2e..0000000000 --- a/app/src/huawei/java/com/owncloud/android/ui/activity/AppScanActivity.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Álvaro Brey Vilas - * Copyright (C) 2022 Álvaro Brey Vilas - * Copyright (C) 2022 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.ui.activity - -import android.Manifest -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import com.owncloud.android.R -import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.PermissionUtil -import com.zynksoftware.documentscanner.ScanActivity -import com.zynksoftware.documentscanner.model.DocumentScannerErrorModel -import com.zynksoftware.documentscanner.model.ScannerResults -import com.zynksoftware.documentscanner.ui.DocumentScanner - -class AppScanActivity : ScanActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - addFragmentContentLayout() - } - - override fun onError(error: DocumentScannerErrorModel) { - DisplayUtils.showSnackMessage(this, R.string.error_starting_scan_doc) - } - - override fun onSuccess(scannerResults: ScannerResults) { - val intent = Intent() - - intent.putExtra( - "file", - scannerResults.transformedImageFile?.absolutePath ?: scannerResults.croppedImageFile?.absolutePath - ) - - setResult(Activity.RESULT_OK, intent) - finish() - } - - override fun onClose() { - finish() - } - - companion object { - @JvmStatic - val enabled: Boolean = true - - @JvmStatic - fun scanFromCamera(activity: Activity, requestCode: Int) { - DocumentScanner.init(activity) - val scanIntent = Intent(activity, AppScanActivity::class.java) - if (PermissionUtil.checkSelfPermission(activity, Manifest.permission.CAMERA)) { - activity.startActivityForResult(scanIntent, requestCode) - } else { - PermissionUtil.requestCameraPermission(activity, PermissionUtil.PERMISSIONS_SCAN_DOCUMENT) - } - } - } -} diff --git a/app/src/main/java/com/nextcloud/client/di/AppComponent.java b/app/src/main/java/com/nextcloud/client/di/AppComponent.java index 73bae85f6b..4ad4bfadeb 100644 --- a/app/src/main/java/com/nextcloud/client/di/AppComponent.java +++ b/app/src/main/java/com/nextcloud/client/di/AppComponent.java @@ -55,6 +55,7 @@ import dagger.android.support.AndroidSupportInjectionModule; ThemeModule.class, DatabaseModule.class, DispatcherModule.class, + VariantModule.class }) @Singleton public interface AppComponent { diff --git a/app/src/main/java/com/nextcloud/client/documentscan/AppScanOptionalFeature.kt b/app/src/main/java/com/nextcloud/client/documentscan/AppScanOptionalFeature.kt new file mode 100644 index 0000000000..c5dbf01bdd --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/documentscan/AppScanOptionalFeature.kt @@ -0,0 +1,45 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2023 Álvaro Brey + * Copyright (C) 2023 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.nextcloud.client.documentscan + +import androidx.activity.result.contract.ActivityResultContract + +abstract class AppScanOptionalFeature { + /** + * Check [isAvailable] before calling this method. + */ + abstract fun getScanContract(): ActivityResultContract + open val isAvailable: Boolean = true + + /** + * Use this in variants where the feature is not available + */ + @Suppress("unused") // used only in some variants + object Stub : AppScanOptionalFeature() { + override fun getScanContract(): ActivityResultContract { + throw UnsupportedOperationException("Document scan is not available") + } + + override val isAvailable = false + } +} diff --git a/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt b/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt index e90e5f34ea..96f78889b5 100644 --- a/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt +++ b/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt @@ -26,6 +26,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem +import androidx.activity.result.ActivityResultLauncher import androidx.appcompat.app.AlertDialog import androidx.core.view.MenuProvider import androidx.lifecycle.ViewModelProvider @@ -39,7 +40,6 @@ import com.owncloud.android.databinding.ActivityDocumentScanBinding import com.owncloud.android.databinding.DialogScanExportTypeBinding import com.owncloud.android.ui.activity.ToolbarActivity import com.owncloud.android.utils.theme.ViewThemeUtils -import com.zynksoftware.documentscanner.ui.DocumentScanner import javax.inject.Inject class DocumentScanActivity : ToolbarActivity(), Injectable { @@ -53,17 +53,22 @@ class DocumentScanActivity : ToolbarActivity(), Injectable { @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var appScanOptionalFeature: AppScanOptionalFeature + lateinit var binding: ActivityDocumentScanBinding lateinit var viewModel: DocumentScanViewModel - private val scanPage = registerForActivityResult(ScanPageContract()) { result -> - viewModel.onScanPageResult(result) - } + private var scanPage: ActivityResultLauncher? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + scanPage = registerForActivityResult(appScanOptionalFeature.getScanContract()) { result -> + viewModel.onScanPageResult(result) + } + val folder = intent.extras?.getString(EXTRA_FOLDER) require(folder != null) { "Folder must be provided for upload" } @@ -72,8 +77,6 @@ class DocumentScanActivity : ToolbarActivity(), Injectable { setupViews() - DocumentScanner.init(this) // TODO this should go back to AppScanActivity, it needs the lib! - observeState() } @@ -203,7 +206,7 @@ class DocumentScanActivity : ToolbarActivity(), Injectable { private fun startPageScan() { logger.d(TAG, "startPageScan() called") viewModel.onScanRequestHandled() - scanPage.launch(Unit) + scanPage!!.launch(Unit) } companion object { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 0ed74a631c..68b92f32a9 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -430,15 +430,6 @@ public class FileDisplayActivity extends FileActivity // toggle on is save since this is the only scenario this code gets accessed } break; - case PermissionUtil.PERMISSIONS_SCAN_DOCUMENT: - // If request is cancelled, result arrays are empty. - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // permission was granted - AppScanActivity.scanFromCamera( - this, - FileDisplayActivity.REQUEST_CODE__UPLOAD_SCAN_DOC_FROM_CAMERA); - } - break; case PermissionUtil.PERMISSIONS_CAMERA: // If request is cancelled, result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { @@ -854,37 +845,6 @@ public class FileDisplayActivity extends FileActivity } } }, new String[]{FileOperationsHelper.createImageFile(getActivity()).getAbsolutePath()}).execute(); - } else if (requestCode == REQUEST_CODE__UPLOAD_SCAN_DOC_FROM_CAMERA && - (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_DELETE)) { - // TODO replace with upload PDF from DocumentScanActivity - - Uri fileUri = Uri.parse(data.getStringExtra("file")); - - new CheckAvailableSpaceTask(new CheckAvailableSpaceTask.CheckAvailableSpaceListener() { - @Override - public void onCheckAvailableSpaceStart() { - Log_OC.d(this, "onCheckAvailableSpaceStart"); - } - - @Override - public void onCheckAvailableSpaceFinish(boolean hasEnoughSpaceAvailable, String... filesToUpload) { - Log_OC.d(this, "onCheckAvailableSpaceFinish"); - - if (hasEnoughSpaceAvailable) { - File file = new File(filesToUpload[0]); - File renamedFile = new File(file.getParent() + PATH_SEPARATOR + FileOperationsHelper.getCapturedImageName()); - - if (!file.renameTo(renamedFile)) { - DisplayUtils.showSnackMessage(getActivity(), "Fail to upload taken image!"); - return; - } - - requestUploadOfFilesFromFileSystem(renamedFile.getParentFile().getAbsolutePath(), - new String[]{renamedFile.getAbsolutePath()}, - FileUploader.LOCAL_BEHAVIOUR_DELETE); - } - } - }, new String[]{fileUri.getPath()}).execute(); } else if (requestCode == REQUEST_CODE__MOVE_FILES && resultCode == RESULT_OK) { exitSelectionMode(); final Intent fData = data; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java index 8f63948794..8a8572e300 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -490,8 +490,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList // return the list of files (success) Intent data = new Intent(); - if (requestCode == FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_CAMERA || - requestCode == FileDisplayActivity.REQUEST_CODE__UPLOAD_SCAN_DOC_FROM_CAMERA) { + if (requestCode == FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_CAMERA) { data.putExtra(EXTRA_CHOSEN_FILES, new String[]{filesToUpload[0]}); setResult(RESULT_OK_AND_DELETE, data); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java index 5ae26c675f..95701987ab 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java @@ -28,6 +28,7 @@ import com.google.gson.Gson; import com.nextcloud.client.account.User; import com.nextcloud.client.device.DeviceInfo; import com.nextcloud.client.di.Injectable; +import com.nextcloud.client.documentscan.AppScanOptionalFeature; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; import com.owncloud.android.databinding.FileListActionsBottomSheetCreatorBinding; @@ -38,7 +39,6 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.common.Creator; import com.owncloud.android.lib.common.DirectEditing; import com.owncloud.android.lib.resources.status.OCCapability; -import com.owncloud.android.ui.activity.AppScanActivity; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.theme.ThemeUtils; @@ -59,6 +59,8 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In private final ViewThemeUtils viewThemeUtils; private final EditorUtils editorUtils; + private final AppScanOptionalFeature appScanOptionalFeature; + public OCFileListBottomSheetDialog(FileActivity fileActivity, OCFileListBottomSheetActions actions, @@ -67,7 +69,8 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In OCFile file, ThemeUtils themeUtils, ViewThemeUtils viewThemeUtils, - EditorUtils editorUtils) { + EditorUtils editorUtils, + AppScanOptionalFeature appScanOptionalFeature) { super(fileActivity); this.actions = actions; this.fileActivity = fileActivity; @@ -77,6 +80,7 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In this.themeUtils = themeUtils; this.viewThemeUtils = viewThemeUtils; this.editorUtils = editorUtils; + this.appScanOptionalFeature = appScanOptionalFeature; } @Override @@ -189,12 +193,12 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In dismiss(); }); - if(AppScanActivity.getEnabled()) { + if (appScanOptionalFeature.isAvailable()) { binding.menuScanDocUpload.setOnClickListener(v -> { actions.scanDocUpload(); dismiss(); }); - }else { + } else { binding.menuScanDocUpload.setVisibility(View.GONE); } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt index 79cd79585d..9890e29995 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt @@ -27,6 +27,7 @@ import androidx.fragment.app.DialogFragment import com.nextcloud.client.account.User import com.nextcloud.client.device.DeviceInfo import com.nextcloud.client.di.Injectable +import com.nextcloud.client.documentscan.AppScanOptionalFeature import com.nextcloud.utils.EditorUtils import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.activity.FileActivity @@ -51,6 +52,9 @@ class OCFileListBottomSheetDialogFragment( @Inject lateinit var editorUtils: EditorUtils + @Inject + lateinit var appScanOptionalFeature: AppScanOptionalFeature + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return OCFileListBottomSheetDialog( fileActivity, @@ -60,7 +64,8 @@ class OCFileListBottomSheetDialogFragment( file, themeUtils, viewThemeUtils, - editorUtils + editorUtils, + appScanOptionalFeature ) } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index bfe27c0018..7b1726e98d 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -77,7 +77,6 @@ import com.owncloud.android.lib.resources.e2ee.ToggleEncryptionRemoteOperation; import com.owncloud.android.lib.resources.files.SearchRemoteOperation; import com.owncloud.android.lib.resources.files.ToggleFavoriteRemoteOperation; import com.owncloud.android.lib.resources.status.OCCapability; -import com.owncloud.android.ui.activity.AppScanActivity; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FolderPickerActivity; diff --git a/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt b/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt index 6466dd51e3..76acf7294d 100644 --- a/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt +++ b/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt @@ -52,7 +52,6 @@ object PermissionUtil { const val PERMISSIONS_CAMERA = 5 const val PERMISSIONS_READ_CALENDAR_AUTOMATIC = 6 const val PERMISSIONS_WRITE_CALENDAR = 7 - const val PERMISSIONS_SCAN_DOCUMENT = 6 const val REQUEST_CODE_MANAGE_ALL_FILES = 19203 diff --git a/app/src/qa/java/com/nextcloud/client/di/VariantModule.kt b/app/src/qa/java/com/nextcloud/client/di/VariantModule.kt new file mode 100644 index 0000000000..c5767a91e0 --- /dev/null +++ b/app/src/qa/java/com/nextcloud/client/di/VariantModule.kt @@ -0,0 +1,37 @@ +/* + * Nextcloud Android client application + * + * @author Chris Narkiewicz + * Copyright (C) 2919 Chris Narkiewicz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + */ +package com.nextcloud.client.di + +import com.nextcloud.appscan.ScanPageContract +import com.nextcloud.client.documentscan.AppScanOptionalFeature +import dagger.Module +import dagger.Provides +import dagger.Reusable + +@Module +internal class VariantModule { + @Provides + @Reusable + fun scanOptionalFeature(): AppScanOptionalFeature { + return object : AppScanOptionalFeature() { + override fun getScanContract() = ScanPageContract() + } + } +} diff --git a/app/src/qa/java/com/owncloud/android/ui/activity/AppScanActivity.kt b/app/src/qa/java/com/owncloud/android/ui/activity/AppScanActivity.kt deleted file mode 100644 index 1d1d1bdb2e..0000000000 --- a/app/src/qa/java/com/owncloud/android/ui/activity/AppScanActivity.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Álvaro Brey Vilas - * Copyright (C) 2022 Álvaro Brey Vilas - * Copyright (C) 2022 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.ui.activity - -import android.Manifest -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import com.owncloud.android.R -import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.PermissionUtil -import com.zynksoftware.documentscanner.ScanActivity -import com.zynksoftware.documentscanner.model.DocumentScannerErrorModel -import com.zynksoftware.documentscanner.model.ScannerResults -import com.zynksoftware.documentscanner.ui.DocumentScanner - -class AppScanActivity : ScanActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - addFragmentContentLayout() - } - - override fun onError(error: DocumentScannerErrorModel) { - DisplayUtils.showSnackMessage(this, R.string.error_starting_scan_doc) - } - - override fun onSuccess(scannerResults: ScannerResults) { - val intent = Intent() - - intent.putExtra( - "file", - scannerResults.transformedImageFile?.absolutePath ?: scannerResults.croppedImageFile?.absolutePath - ) - - setResult(Activity.RESULT_OK, intent) - finish() - } - - override fun onClose() { - finish() - } - - companion object { - @JvmStatic - val enabled: Boolean = true - - @JvmStatic - fun scanFromCamera(activity: Activity, requestCode: Int) { - DocumentScanner.init(activity) - val scanIntent = Intent(activity, AppScanActivity::class.java) - if (PermissionUtil.checkSelfPermission(activity, Manifest.permission.CAMERA)) { - activity.startActivityForResult(scanIntent, requestCode) - } else { - PermissionUtil.requestCameraPermission(activity, PermissionUtil.PERMISSIONS_SCAN_DOCUMENT) - } - } - } -} diff --git a/app/src/versionDev/java/com/nextcloud/client/di/VariantModule.kt b/app/src/versionDev/java/com/nextcloud/client/di/VariantModule.kt new file mode 100644 index 0000000000..d9d2703668 --- /dev/null +++ b/app/src/versionDev/java/com/nextcloud/client/di/VariantModule.kt @@ -0,0 +1,34 @@ +/* + * Nextcloud Android client application + * + * @author Chris Narkiewicz + * Copyright (C) 2919 Chris Narkiewicz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + */ +package com.nextcloud.client.di + +import com.nextcloud.client.documentscan.AppScanOptionalFeature +import dagger.Module +import dagger.Provides +import dagger.Reusable + +@Module +internal class VariantModule { + @Provides + @Reusable + fun scanOptionalFeature(): AppScanOptionalFeature { + return AppScanOptionalFeature.Stub + } +} diff --git a/app/src/versionDev/java/com/owncloud/android/ui/activity/AppScanActivity.kt b/app/src/versionDev/java/com/owncloud/android/ui/activity/AppScanActivity.kt deleted file mode 100644 index 6f6bd620f9..0000000000 --- a/app/src/versionDev/java/com/owncloud/android/ui/activity/AppScanActivity.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Álvaro Brey Vilas - * Copyright (C) 2022 Álvaro Brey Vilas - * Copyright (C) 2022 Nextcloud GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.owncloud.android.ui.activity - -import android.app.Activity -import com.owncloud.android.lib.common.utils.Log_OC - -class AppScanActivity { - // stub - companion object { - private val TAG = AppScanActivity::class.simpleName - - @JvmStatic - val enabled: Boolean = false - - @JvmStatic - fun scanFromCamera(activity: Activity, requestcode: Int) { - // stub - Log_OC.w(TAG, "scanFromCamera called in stub implementation") - } - } -} diff --git a/appscan/.gitignore b/appscan/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/appscan/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/appscan/build.gradle b/appscan/build.gradle new file mode 100644 index 0000000000..daa973eed3 --- /dev/null +++ b/appscan/build.gradle @@ -0,0 +1,41 @@ +buildscript { + dependencies { + classpath "com.android.tools.build:gradle:$androidPluginVersion" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + namespace 'com.nextcloud.appscan' + compileSdk 33 + + defaultConfig { + minSdk 21 + targetSdk 33 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + implementation "androidx.appcompat:appcompat:$appCompatVersion" + implementation "com.github.zynkware:Document-Scanning-Android-SDK:$documentScannerVersion" +} diff --git a/appscan/consumer-rules.pro b/appscan/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/appscan/proguard-rules.pro b/appscan/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/appscan/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/appscan/src/main/AndroidManifest.xml b/appscan/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..b351d9a623 --- /dev/null +++ b/appscan/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/appscan/src/main/java/com/nextcloud/appscan/AppScanActivity.kt b/appscan/src/main/java/com/nextcloud/appscan/AppScanActivity.kt new file mode 100644 index 0000000000..81915a9c73 --- /dev/null +++ b/appscan/src/main/java/com/nextcloud/appscan/AppScanActivity.kt @@ -0,0 +1,67 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2023 Álvaro Brey + * Copyright (C) 2023 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.nextcloud.appscan + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import com.zynksoftware.documentscanner.ScanActivity +import com.zynksoftware.documentscanner.model.DocumentScannerErrorModel +import com.zynksoftware.documentscanner.model.ScannerResults +import com.zynksoftware.documentscanner.ui.DocumentScanner + +@Suppress("unused") +class AppScanActivity : ScanActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + DocumentScanner.init(this) + addFragmentContentLayout() + } + + override fun onError(error: DocumentScannerErrorModel) { + // TODO pass this from app somehow? + } + + override fun onSuccess(scannerResults: ScannerResults) { + val intent = Intent() + + intent.putExtra( + EXTRA_FILE, + scannerResults.transformedImageFile?.absolutePath ?: scannerResults.croppedImageFile?.absolutePath + ) + + setResult(Activity.RESULT_OK, intent) + finish() + } + + override fun onClose() { + finish() + } + + companion object { + @JvmStatic + val enabled: Boolean = true + + const val EXTRA_FILE = "file" + } +} diff --git a/app/src/main/java/com/nextcloud/client/documentscan/ScanPageContract.kt b/appscan/src/main/java/com/nextcloud/appscan/ScanPageContract.kt similarity index 93% rename from app/src/main/java/com/nextcloud/client/documentscan/ScanPageContract.kt rename to appscan/src/main/java/com/nextcloud/appscan/ScanPageContract.kt index c81d983393..9bd4271e5d 100644 --- a/app/src/main/java/com/nextcloud/client/documentscan/ScanPageContract.kt +++ b/appscan/src/main/java/com/nextcloud/appscan/ScanPageContract.kt @@ -20,13 +20,12 @@ * */ -package com.nextcloud.client.documentscan +package com.nextcloud.appscan import android.app.Activity import android.content.Context import android.content.Intent import androidx.activity.result.contract.ActivityResultContract -import com.owncloud.android.ui.activity.AppScanActivity class ScanPageContract : ActivityResultContract() { override fun createIntent(context: Context, input: Unit): Intent { diff --git a/build.gradle b/build.gradle index 937f55b808..8b37ad936d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,7 @@ buildscript { ext { + androidPluginVersion = '7.4.0' + appCompatVersion = '1.6.0' jacoco_version = '0.8.8' kotlin_version = '1.7.22' androidxTestVersion = "1.4.0" diff --git a/settings.gradle b/settings.gradle index bb095760cc..367bea7074 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,7 @@ rootProject.name = 'Nextcloud' include ':app' +include ':appscan' //includeBuild('../android-common') { // dependencySubstitution {