diff --git a/capture-sdk/sdk/src/main/AndroidManifest.xml b/capture-sdk/sdk/src/main/AndroidManifest.xml
index 06676c4b5d..dc5ba0412a 100644
--- a/capture-sdk/sdk/src/main/AndroidManifest.xml
+++ b/capture-sdk/sdk/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
@@ -18,6 +19,16 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/capture-sdk/sdk/src/main/java/net/gini/android/capture/camera/CameraFragmentImpl.java b/capture-sdk/sdk/src/main/java/net/gini/android/capture/camera/CameraFragmentImpl.java
index 9c463df50a..4f4c0f3993 100644
--- a/capture-sdk/sdk/src/main/java/net/gini/android/capture/camera/CameraFragmentImpl.java
+++ b/capture-sdk/sdk/src/main/java/net/gini/android/capture/camera/CameraFragmentImpl.java
@@ -456,6 +456,8 @@ private void setFileChooserFragmentResultListener() {
public void handleFileChooserResult(@NonNull FileChooserResult result) {
if (result instanceof FileChooserResult.FilesSelected) {
importDocumentFromIntent(((FileChooserResult.FilesSelected) result).getDataIntent());
+ } else if(result instanceof FileChooserResult.FilesSelectedUri) {
+ importDocumentFromUriList(((FileChooserResult.FilesSelectedUri) result).getList());
} else if (result instanceof FileChooserResult.Error) {
final GiniCaptureError error = ((FileChooserResult.Error) result).getError();
final String message = "Document import failed: " + error.getMessage();
@@ -1113,6 +1115,13 @@ private void importDocumentFromIntent(@NonNull final Intent data) {
}
}
+ private void importDocumentFromUriList(List uriList) {
+ if (mFragment.getActivity() == null)
+ return;
+
+ handleMultiPageDocumentAndCallListener(mFragment.getActivity(), new Intent(Intent.ACTION_PICK), uriList);
+ }
+
private boolean isImage(@NonNull final Intent data, @NonNull final Activity activity) {
return IntentHelper.hasMimeTypeWithPrefix(data, activity, MimeType.IMAGE_PREFIX.asString());
}
diff --git a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/FileChooserFragment.kt b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/FileChooserFragment.kt
index 996a41d5f0..c9cc710387 100644
--- a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/FileChooserFragment.kt
+++ b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/FileChooserFragment.kt
@@ -7,6 +7,7 @@ import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.content.pm.ResolveInfo
+import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Parcelable
@@ -15,7 +16,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.content.ContextCompat
import androidx.fragment.app.setFragmentResult
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
@@ -30,6 +33,7 @@ import net.gini.android.capture.R
import net.gini.android.capture.databinding.GcFragmentFileChooserBinding
import net.gini.android.capture.internal.fileimport.providerchooser.ProvidersAdapter
import net.gini.android.capture.internal.fileimport.providerchooser.ProvidersAppItem
+import net.gini.android.capture.internal.fileimport.providerchooser.ProvidersAppWrapperItem
import net.gini.android.capture.internal.fileimport.providerchooser.ProvidersItem
import net.gini.android.capture.internal.fileimport.providerchooser.ProvidersSectionItem
import net.gini.android.capture.internal.fileimport.providerchooser.ProvidersSeparatorItem
@@ -52,6 +56,7 @@ class FileChooserFragment : BottomSheetDialogFragment() {
private var docImportEnabledFileTypes: DocumentImportEnabledFileTypes? = null
private var binding: GcFragmentFileChooserBinding by autoCleared()
private var chooseFileLauncher: ActivityResultLauncher? = null
+ private var pickMedia: ActivityResultLauncher? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -139,6 +144,32 @@ class FileChooserFragment : BottomSheetDialogFragment() {
})
}
}
+
+ val photoPickType =
+ if (FeatureConfiguration.isMultiPageEnabled())
+ ActivityResultContracts.PickMultipleVisualMedia()
+ else
+ ActivityResultContracts.PickVisualMedia()
+
+
+ pickMedia = registerForActivityResult(photoPickType) { uri ->
+ findNavController().popBackStack()
+ if (uri != null) {
+ val lst = when(uri){
+ is Uri -> listOf(uri)
+ is List<*> -> uri.filterIsInstance().takeIf { it.size == uri.size }
+ ?: throw IllegalArgumentException("List contains non-Uri elements")
+ else -> throw IllegalArgumentException("uri is neither Uri nor List")
+ }
+ setFragmentResult(REQUEST_KEY, Bundle().apply {
+ putParcelable(RESULT_KEY, FileChooserResult.FilesSelectedUri(lst))
+ })
+ } else {
+ setFragmentResult(REQUEST_KEY, Bundle().apply {
+ putParcelable(RESULT_KEY, FileChooserResult.Cancelled)
+ })
+ }
+ }
}
private fun getGridSpanCount(): Int =
@@ -151,15 +182,18 @@ class FileChooserFragment : BottomSheetDialogFragment() {
private fun populateFileProviders() {
val providerItems: MutableList = ArrayList()
- var imageProviderItems: List = ArrayList()
+ var imageProviderItems: List = arrayListOf()
var pdfProviderItems: List = ArrayList()
if (shouldShowImageProviders()) {
val imagePickerResolveInfos = queryImagePickers(requireContext())
val imageProviderResolveInfos = queryImageProviders(requireContext())
- imageProviderItems = getImageProviderItems(
- imagePickerResolveInfos,
- imageProviderResolveInfos
- )
+
+ imageProviderItems =
+ if (ActivityResultContracts.PickVisualMedia.isPhotoPickerAvailable(requireContext())) {
+ getPhotoPickerProvider()
+ } else {
+ getImageProviderItems(imagePickerResolveInfos, imageProviderResolveInfos)
+ }
}
if (shouldShowPdfProviders()) {
val pdfProviderResolveInfos = queryPdfProviders(requireContext())
@@ -172,15 +206,31 @@ class FileChooserFragment : BottomSheetDialogFragment() {
providerItems.addAll(pdfProviderItems)
(binding.gcFileProviders.layoutManager as GridLayoutManager).spanSizeLookup =
ProvidersSpanSizeLookup(providerItems, getGridSpanCount())
- binding.gcFileProviders.adapter = ProvidersAdapter(requireContext(), providerItems) { item -> launchApp(item) }
+ binding.gcFileProviders.adapter = ProvidersAdapter(requireContext(), providerItems) {
+ item -> launchApp(item)
+ }
}
- private fun launchApp(item: ProvidersAppItem) {
- item.intent.setClassName(
- item.resolveInfo.activityInfo.packageName,
- item.resolveInfo.activityInfo.name
- )
- chooseFileLauncher?.launch(item.intent)
+ private fun launchApp(item: ProvidersItem) {
+ when (item) {
+ is ProvidersAppItem -> {
+ item.intent.setClassName(
+ item.resolveInfo.activityInfo.packageName,
+ item.resolveInfo.activityInfo.name
+ )
+ chooseFileLauncher?.launch(item.intent)
+ }
+
+ is ProvidersAppWrapperItem -> {
+ pickMedia?.launch(
+ PickVisualMediaRequest(
+ ActivityResultContracts.PickVisualMedia.SingleMimeType(
+ MimeType.IMAGE_WILDCARD.asString()
+ )
+ )
+ )
+ }
+ }
}
private fun getImageProviderItems(
@@ -204,6 +254,23 @@ class FileChooserFragment : BottomSheetDialogFragment() {
}
}
+ private fun getPhotoPickerProvider(): List {
+ val providerList =
+ ContextCompat.getDrawable(requireContext(), (R.drawable.gc_photo_tip_align))
+ ?.let { image ->
+ listOf(
+ ProvidersSectionItem(getString(R.string.gc_file_chooser_fotos_section_header)),
+ ProvidersAppWrapperItem(
+ image,
+ getString(R.string.gc_file_chooser_fotos_section_header)
+ )
+ )
+ } ?: run {
+ emptyList()
+ }
+ return providerList
+ }
+
private fun getPdfProviderItems(pdfProviderResolveInfos: List): List =
mutableListOf().apply {
if (pdfProviderResolveInfos.isNotEmpty()) {
@@ -311,6 +378,7 @@ class FileChooserFragment : BottomSheetDialogFragment() {
@Parcelize
sealed class FileChooserResult : Parcelable {
data class FilesSelected(val dataIntent: Intent) : FileChooserResult()
+ data class FilesSelectedUri(val list: List) : FileChooserResult()
data class Error(val error: GiniCaptureError) : FileChooserResult()
object Cancelled : FileChooserResult()
}
diff --git a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAdapter.java b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAdapter.java
index 7a672cb21f..37270307fa 100644
--- a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAdapter.java
+++ b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAdapter.java
@@ -40,12 +40,14 @@ public int getItemViewType(final int position) {
@Override
public ProvidersItemViewHolder onCreateViewHolder(final ViewGroup parent,
- final int viewType) {
+ final int viewType) {
switch (ProvidersItem.FileProviderItemType.fromOrdinal(viewType)) {
case SECTION:
return createSectionItemViewHolder(parent);
case APP:
- return createAppItemViewHolder(parent);
+ return createAppItemViewHolder(parent, ProvidersItem.FileProviderItemType.APP);
+ case APP_WRAPPER_PHOTO_PICKER:
+ return createAppItemViewHolder(parent, ProvidersItem.FileProviderItemType.APP_WRAPPER_PHOTO_PICKER);
case SEPARATOR:
return createSeparatorItemViewHolder(parent);
default:
@@ -62,10 +64,12 @@ private ProvidersItemViewHolder createSectionItemViewHolder(
}
@NonNull
- private ProvidersItemViewHolder createAppItemViewHolder(@NonNull final ViewGroup parent) {
+ private ProvidersItemViewHolder createAppItemViewHolder(
+ @NonNull final ViewGroup parent,
+ @NonNull ProvidersItem.FileProviderItemType providerItemType) {
final View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.gc_item_file_provider_app, parent, false);
- return new ProvidersAppItemViewHolder(itemView);
+ return new ProvidersAppItemViewHolder(itemView, providerItemType);
}
private ProvidersItemViewHolder createSeparatorItemViewHolder(@NonNull final ViewGroup parent) {
@@ -83,6 +87,8 @@ public void onBindViewHolder(final ProvidersItemViewHolder holder, final int pos
case APP:
bindAppItemViewHolder((ProvidersAppItemViewHolder) holder, position);
break;
+ case APP_WRAPPER_PHOTO_PICKER:
+ bindAppWrapperItemViewHolder((ProvidersAppItemViewHolder) holder, position);
case SEPARATOR:
break;
default:
@@ -101,13 +107,22 @@ private void bindAppItemViewHolder(@NonNull final ProvidersAppItemViewHolder hol
final ProvidersAppItem item = (ProvidersAppItem) mItems.get(position);
holder.icon.setImageDrawable(item.getResolveInfo().loadIcon(mContext.getPackageManager()));
holder.label.setText(item.getResolveInfo().loadLabel(mContext.getPackageManager()));
- holder.itemView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(final View view) {
- final ProvidersAppItem item =
- (ProvidersAppItem) mItems.get(holder.getAdapterPosition());
- mItemSelectedListener.onItemSelected(item);
- }
+ holder.itemView.setOnClickListener(view -> {
+ final ProvidersAppItem item1 =
+ (ProvidersAppItem) mItems.get(holder.getAdapterPosition());
+ mItemSelectedListener.onItemSelected(item1);
+ });
+ }
+
+ private void bindAppWrapperItemViewHolder(@NonNull final ProvidersAppItemViewHolder holder,
+ final int position) {
+ final ProvidersAppWrapperItem item = (ProvidersAppWrapperItem) mItems.get(position);
+ holder.icon.setImageDrawable(item.getDrawableIcon());
+ holder.label.setText(item.getText());
+ holder.itemView.setOnClickListener(view -> {
+ final ProvidersAppWrapperItem item1 =
+ (ProvidersAppWrapperItem) mItems.get(holder.getAdapterPosition());
+ mItemSelectedListener.onItemSelected(item1);
});
}
@@ -123,8 +138,8 @@ private static class ProvidersAppItemViewHolder extends ProvidersItemViewHolder
@NonNull
final TextView label;
- ProvidersAppItemViewHolder(@NonNull final View itemView) {
- super(itemView, ProvidersItem.FileProviderItemType.APP);
+ ProvidersAppItemViewHolder(@NonNull final View itemView, @NonNull ProvidersItem.FileProviderItemType providerItemType) {
+ super(itemView, providerItemType);
icon = itemView.findViewById(R.id.gc_app_icon);
label = itemView.findViewById(R.id.gc_app_label);
}
diff --git a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAppItemSelectedListener.java b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAppItemSelectedListener.java
index 9324d0de5b..f6e16751ef 100644
--- a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAppItemSelectedListener.java
+++ b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAppItemSelectedListener.java
@@ -9,5 +9,5 @@
*/
public interface ProvidersAppItemSelectedListener {
- void onItemSelected(@NonNull final ProvidersAppItem item);
+ void onItemSelected(@NonNull final ProvidersItem item);
}
diff --git a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAppWrapperItem.java b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAppWrapperItem.java
new file mode 100644
index 0000000000..7dee3c5b82
--- /dev/null
+++ b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersAppWrapperItem.java
@@ -0,0 +1,31 @@
+package net.gini.android.capture.internal.fileimport.providerchooser;
+
+import android.graphics.drawable.Drawable;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Internal use only.
+ *
+ * @suppress
+ */
+public class ProvidersAppWrapperItem extends ProvidersItem {
+
+ private final Drawable mIcon;
+ private final String mText;
+
+ public ProvidersAppWrapperItem(@NonNull final Drawable icon, @NonNull final String text) {
+ super(FileProviderItemType.APP_WRAPPER_PHOTO_PICKER);
+ mIcon = icon;
+ mText = text;
+ }
+
+ public Drawable getDrawableIcon() {
+ return mIcon;
+ }
+
+ public String getText() {
+ return mText;
+ }
+
+}
diff --git a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersItem.java b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersItem.java
index 97749a19a3..408c20573b 100644
--- a/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersItem.java
+++ b/capture-sdk/sdk/src/main/java/net/gini/android/capture/internal/fileimport/providerchooser/ProvidersItem.java
@@ -53,7 +53,8 @@ FileProviderItemType getType() {
enum FileProviderItemType {
SECTION,
SEPARATOR,
- APP;
+ APP,
+ APP_WRAPPER_PHOTO_PICKER;
static FileProviderItemType fromOrdinal(final int ordinal) {
if (ordinal >= values().length) {