Move optional appscan feature to a separate module to avoid duplicating code between variants

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 <alvaro.brey@nextcloud.com>
This commit is contained in:
Álvaro Brey 2023-01-20 16:43:28 +01:00
parent 9478fb15e9
commit 1917198305
No known key found for this signature in database
GPG Key ID: 2585783189A62105
29 changed files with 417 additions and 379 deletions

View File

@ -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'

View File

@ -0,0 +1,34 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz
* Copyright (C) 2919 Chris Narkiewicz <hello@ezaquarii.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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")
}
}
}

View File

@ -0,0 +1,37 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz
* Copyright (C) 2919 Chris Narkiewicz <hello@ezaquarii.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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()
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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)
}
}
}
}

View File

@ -0,0 +1,37 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz
* Copyright (C) 2919 Chris Narkiewicz <hello@ezaquarii.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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()
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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)
}
}
}
}

View File

@ -55,6 +55,7 @@ import dagger.android.support.AndroidSupportInjectionModule;
ThemeModule.class,
DatabaseModule.class,
DispatcherModule.class,
VariantModule.class
})
@Singleton
public interface AppComponent {

View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
package com.nextcloud.client.documentscan
import androidx.activity.result.contract.ActivityResultContract
abstract class AppScanOptionalFeature {
/**
* Check [isAvailable] before calling this method.
*/
abstract fun getScanContract(): ActivityResultContract<Unit, String?>
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<Unit, String?> {
throw UnsupportedOperationException("Document scan is not available")
}
override val isAvailable = false
}
}

View File

@ -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<Unit>? = 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 {

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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
)
}
}

View File

@ -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;

View File

@ -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

View File

@ -0,0 +1,37 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz
* Copyright (C) 2919 Chris Narkiewicz <hello@ezaquarii.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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()
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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)
}
}
}
}

View File

@ -0,0 +1,34 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz
* Copyright (C) 2919 Chris Narkiewicz <hello@ezaquarii.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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")
}
}
}

1
appscan/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

41
appscan/build.gradle Normal file
View File

@ -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"
}

View File

21
appscan/proguard-rules.pro vendored Normal file
View File

@ -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

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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 <http://www.gnu.org/licenses/>.
~
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity android:name=".AppScanActivity" />
</application>
</manifest>

View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
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"
}
}

View File

@ -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<Unit, String?>() {
override fun createIntent(context: Context, input: Unit): Intent {

View File

@ -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"

View File

@ -1,6 +1,7 @@
rootProject.name = 'Nextcloud'
include ':app'
include ':appscan'
//includeBuild('../android-common') {
// dependencySubstitution {