diff --git a/cameralibrary/src/main/AndroidManifest.xml b/cameralibrary/src/main/AndroidManifest.xml index 27442db..b0c62dd 100644 --- a/cameralibrary/src/main/AndroidManifest.xml +++ b/cameralibrary/src/main/AndroidManifest.xml @@ -1,2 +1,18 @@ + + package="com.devtk.tk2232.EasyImagePicker"> + + + + + + + + + \ No newline at end of file diff --git a/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/Callbacks.java b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/Callbacks.java new file mode 100644 index 0000000..e0b8561 --- /dev/null +++ b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/Callbacks.java @@ -0,0 +1,14 @@ +package com.devtk.cameralibrary.ImagePicker; + +import android.support.annotation.NonNull; + +import java.io.File; +import java.util.List; + +public interface Callbacks { + void onImagesPicked(@NonNull List files, ImageSource imageSource, int type); + + void onCanceled(ImageSource imageSource, int type); + + void onImagePickerError(Exception e, ImageSource imageSource, int type); +} \ No newline at end of file diff --git a/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/DefaultCallback.java b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/DefaultCallback.java new file mode 100644 index 0000000..a50f279 --- /dev/null +++ b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/DefaultCallback.java @@ -0,0 +1,4 @@ +package com.devtk.cameralibrary.ImagePicker; + +public abstract class DefaultCallback implements Callbacks { +} diff --git a/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/FileConfiguration.java b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/FileConfiguration.java new file mode 100644 index 0000000..46b60a3 --- /dev/null +++ b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/FileConfiguration.java @@ -0,0 +1,171 @@ +package com.devtk.cameralibrary.ImagePicker; + +import android.app.Activity; +import android.content.Context; +import android.os.Environment; +import android.support.annotation.NonNull; + +import com.devtk.tk2232.EasyImagePicker.R; + +public class FileConfiguration { + + private String TAG; + + /** + * Coniguration + */ + private String EXTERNAL_FOLDER_PATH_DEFAULT; + + /** + * DIRECTORY_MUSIC + * DIRECTORY_PODCASTS + * DIRECTORY_RINGTONES + * DIRECTORY_ALARMS + * DIRECTORY_NOTIFICATIONS + * DIRECTORY_PICTURES damit gibt es probleme beim auslesen onActivityResult + * DIRECTORY_MOVIES + * DIRECTORY_DOWNLOADS + * DIRECTORY_DCIM + * DIRECTORY_DOCUMENTS + */ + private final String ENVIRONMENT_DEFAULT = Environment.DIRECTORY_DCIM; + private final boolean CREATE_TEMP_FILE_DEFAULT = true; + private final String SUFFIX_DEFAULT = ".jpg"; + private final boolean AUTO_IMAGE_FILE_NAME_DEFAULT = true; + private String INERNAL_IMAGE_TEMP_FILENAME_DEFAULT = "tempImage"; + private final String PRIVATE_TEMP_FILE_PATH_CHILD_DEFAULT = "ImageTemp"; + private final boolean WRITE_TO_EXTERNAL_STORRAGE_DEFAULT = true; + + private String folderPath; + private String environment; + private boolean createTempFile; + private boolean autoImageFileName; + private String internalImageFilename; + private String privateTempFilePathChild; + private String imageFileName; + private String suffix; + private boolean writeToExternalStorrage; + private ImageLogCallback imageLogCallback; + + private Context context; + + public FileConfiguration(@NonNull Context context) { + this.context = context; + TAG = context.getClass().getSimpleName(); + EXTERNAL_FOLDER_PATH_DEFAULT = ((Activity) context).getText(R.string.app_name).toString(); + setDefaultConfig(); + } + + public void setDefaultConfig() { + folderPath = EXTERNAL_FOLDER_PATH_DEFAULT; + environment = ENVIRONMENT_DEFAULT; + createTempFile = CREATE_TEMP_FILE_DEFAULT; + autoImageFileName = AUTO_IMAGE_FILE_NAME_DEFAULT; + internalImageFilename = INERNAL_IMAGE_TEMP_FILENAME_DEFAULT; + privateTempFilePathChild = PRIVATE_TEMP_FILE_PATH_CHILD_DEFAULT; + suffix = SUFFIX_DEFAULT; + writeToExternalStorrage = WRITE_TO_EXTERNAL_STORRAGE_DEFAULT; + imageFileName = ""; + imageLogCallback = null; + } + + public FileConfiguration folderPath(String folderPath) { + this.folderPath = folderPath; + return this; + } + + public FileConfiguration environment(String environment) { + this.environment = environment; + return this; + } + + public FileConfiguration createTempFile(boolean createTempFile) { + this.createTempFile = createTempFile; + return this; + } + + public FileConfiguration setAutoImageFileName(boolean autoImageFileName) { + this.autoImageFileName = autoImageFileName; + return this; + } + + public FileConfiguration internalImageFilename(String internalImageFilename) { + this.internalImageFilename = internalImageFilename; + return this; + } + + public FileConfiguration privateTempFilePathChild(String privateTempFilePathChild) { + this.privateTempFilePathChild = privateTempFilePathChild; + return this; + } + + public FileConfiguration imageFileName(String imageFileName) { + this.imageFileName = imageFileName; + this.autoImageFileName = true; + return this; + } + + public FileConfiguration writeToExternalStorrage(boolean writeToExternalStorrage) { + this.writeToExternalStorrage = writeToExternalStorrage; + return this; + } + + public FileConfiguration suffix(String suffix) { + this.suffix = suffix; + return this; + } + + public FileConfiguration logCallback(ImageLogCallback imageLogCallback) { + this.imageLogCallback = imageLogCallback; + return this; + } + + public String getTAG() { + return TAG; + } + + public String getFolderPath() { + return folderPath; + } + + public String getEnvironment() { + return environment; + } + + @Deprecated + public boolean isCreateTempFile() { + return createTempFile; + } + + public boolean isAutoImageFileName() { + return autoImageFileName; + } + + public String getInternalImageFilename() { + return internalImageFilename; + } + + public String getPrivateTempFilePathChild() { + return privateTempFilePathChild; + } + + public String getImageFileName() { + return imageFileName; + } + + public String getSuffix() { + return suffix; + } + + public boolean isWriteToExternalStorrage() { + return writeToExternalStorrage; + } + + public Context getContext() { + return context; + } + + public ImageLogCallback getImageLogCallback() { + return imageLogCallback; + } +} diff --git a/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/FileHelper.java b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/FileHelper.java new file mode 100644 index 0000000..fa47855 --- /dev/null +++ b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/FileHelper.java @@ -0,0 +1,331 @@ +package com.devtk.cameralibrary.ImagePicker; + +import android.content.ContentResolver; +import android.content.Context; +import android.media.MediaScannerConnection; +import android.net.Uri; +import android.os.Environment; +import android.support.annotation.NonNull; +import android.support.v4.content.FileProvider; +import android.util.Log; +import android.webkit.MimeTypeMap; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +public class FileHelper { + + private static final String TAG = FileHelper.class.getSimpleName(); + + /** + * Erstellt ein im internal storrage ein Tempfile + * + * @param config + * @return + * @throws IOException + */ + public static File getCameraTempFile(@NonNull FileConfiguration config) throws IOException { + File dir = getTempImageDirectory(config); + return new File(dir + File.separator + config.getInternalImageFilename() + config.getSuffix()); + } + + /** + * Gibt den Ordner vom private internal storrage zurück + * + * @param config + * @return + */ + public static File getTempImageDirectory(@NonNull FileConfiguration config) { + File privateTempDir = new File(config.getContext().getFilesDir(), config.getPrivateTempFilePathChild()); + if (!privateTempDir.exists()) { + privateTempDir.mkdirs(); + } + return privateTempDir; + } + + /** + * Gibt die Uri vom fileprovider wieder. Fileprovider muss in der Manifest angemeldet werden + * + * @param config + * @param file + * @return + */ + public static Uri getUriToFile(@NonNull FileConfiguration config, @NonNull File file) { + String packageName = config.getContext().getApplicationContext().getPackageName(); + String authority = packageName + ".fileprovider"; + + return FileProvider.getUriForFile(config.getContext(), authority, file); + } + + /** + * Copiert das Foto auf den external storrage + * + * @param config + * @param photoUri + * @return + * @throws IOException + */ + public static File pickedExistingPicture(@NonNull FileConfiguration config, Uri photoUri) throws IOException { + InputStream pictureInputStream = config.getContext().getContentResolver().openInputStream(photoUri); + File directory = getTempImageDirectory(config); + File photoFile = new File(directory, UUID.randomUUID().toString() + "." + getMimeType(config.getContext(), photoUri)); + photoFile.createNewFile(); + writeToFile(pictureInputStream, photoFile); + return photoFile; + } + + @Deprecated + public static File getCameraPicturesLocation(@NonNull FileConfiguration config) throws IOException { + File dir = getTempImageDirectory(config); + return File.createTempFile(UUID.randomUUID().toString(), ".jpg", dir); + } + +// public static File tempCacheImageDirectory(@NonNull Context context) { +// configuration(context); +// File privateTempDir = new File(context.getCacheDir(), PRIVATE_TEMP_FILE_CHILD_DEFAULT); +// if (!privateTempDir.exists()) { +// privateTempDir.mkdirs(); +// } +// return privateTempDir; +// } + + private static void writeToFile(InputStream in, File file) { + try { + OutputStream out = new FileOutputStream(file); + byte[] buf = new byte[1024]; + + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + + out.close(); + in.close(); + } catch (Exception var5) { + var5.printStackTrace(); + } + + } + + private static String getMimeType(@NonNull Context context, @NonNull Uri uri) { + String extension; + if (uri.getScheme().equals("content")) { + MimeTypeMap mime = MimeTypeMap.getSingleton(); + extension = mime.getExtensionFromMimeType(context.getContentResolver().getType(uri)); + } else { + extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(uri.getPath())).toString()); + } + return extension; + } + + public static void copyFilesInSeparateThread(final FileConfiguration config, final List filesToCopy) { + (new Thread(new Runnable() { + public void run() { + List copiedFiles = new ArrayList(); + int i = 1; + + for (Iterator iterator = filesToCopy.iterator(); iterator.hasNext(); ++i) { + File fileToCopy = (File) iterator.next(); + File dstDir = new File(Environment.getExternalStoragePublicDirectory(config.getEnvironment()), config.getFolderPath()); + if (!dstDir.exists()) { + dstDir.mkdirs(); + } + + String[] filenameSplit = fileToCopy.getName().split("\\."); + String extension = "." + filenameSplit[filenameSplit.length - 1]; +// String filename = String.format("IMG_%s_%d.%s", (new SimpleDateFormat("yyyyMMdd_HHmmss")).format(Calendar.getInstance().getTime()), i, extension); + String filename = getImageFileName(config) + config.getSuffix(); + File dstFile = new File(dstDir, filename); + + try { + dstFile.createNewFile(); + copyFile(fileToCopy, dstFile); + copiedFiles.add(dstFile); + } catch (IOException var11) { + var11.printStackTrace(); + } + } + scanCopiedImages(config.getContext(), copiedFiles); + } + })).run(); + } + + private static void copyFile(File src, File dst) throws IOException { + InputStream in = new FileInputStream(src); + writeToFile(in, dst); + } + + static void scanCopiedImages(Context context, List copiedImages) { + String[] paths = new String[copiedImages.size()]; + + for (int i = 0; i < copiedImages.size(); ++i) { + paths[i] = ((File) copiedImages.get(i)).toString(); + } + + MediaScannerConnection.scanFile(context, paths, (String[]) null, new MediaScannerConnection.OnScanCompletedListener() { + public void onScanCompleted(String path, Uri uri) { + Log.d(this.getClass().getSimpleName(), "Scanned " + path + ":"); + Log.d(this.getClass().getSimpleName(), "-> uri=" + uri); + } + }); + } + + @Deprecated + public static File getTempImageFile(@NonNull FileConfiguration config) throws IOException { + if (config.isWriteToExternalStorrage()) { + if (isExternalStorageReadable() && isExternalStorageWritable()) { + File file = new File(config.getContext().getFilesDir(), config.getInternalImageFilename() + config.getSuffix()); + return file; + } else { + log(config, TAG, "getTempImageFile read/write error"); + } + } else { + + } + return null; + } + + @Deprecated + public static File getImageFile(FileConfiguration config) throws IOException { + // Create an image file name + if (config.isWriteToExternalStorrage()) { + if (isExternalStorageReadable() && isExternalStorageWritable()) { + return createImageFile(config); + } else { + log(config, TAG, "getTempImageFile read/write error"); + } + } else { + + } + return null; + } + + @Deprecated + public static File createImageFile(FileConfiguration config) throws IOException { + File folderPath = createExternalPublicFolder(config); + if (folderPath == null) { + return null; + } + if (config.isCreateTempFile()) { + File image = File.createTempFile(getImageFileName(config), config.getSuffix(), createExternalPublicFolder(config)); + return image; + } else { + File image = new File(createExternalPublicFolder(config), getImageFileName(config) + config.getSuffix()); + return image; + } + } + + /** + * Erstellt einen Ordner auf dem externen Speicher falls dieser noch nicht exestiert + * + * @return FolderPath + */ + private static File createExternalPublicFolder(@NonNull FileConfiguration config) { + //Ref. https://stackoverflow.com/questions/22366217/cant-create-folder-on-external-storage-on-android +// File file = new File(Environment.getExternalStorageDirectory() + File.separator + FOLDER_PATH); + File file = new File(Environment.getExternalStoragePublicDirectory(config.getEnvironment()) + File.separator + config.getFolderPath()); + + if (!file.exists()) { + Log.d(TAG, "Folder doesn't exist, creating it..."); + boolean rv = file.mkdir(); + Log.d(TAG, "Folder creation " + (rv ? "success" : "failed")); +// if (!rv) { +// return null; +// } + } else { + Log.d(TAG, "Folder already exists."); + } + return file; + } + + /* Checks if external storage is available for read and write */ + public static boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + return false; + } + + /* Checks if external storage is available to at least read */ + public static boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state) || + Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + return true; + } + return false; + } + + public static boolean removeFile(@NonNull FileConfiguration config, @NonNull File file) { + try { + if (file.exists()) { + if (file.delete()) { + return true; + } else { + return false; + } + } + } catch (NullPointerException e) { + log(config, config.getContext().getClass().getSimpleName(), e.getMessage(), e); + } + return false; + } + + /** + * Test if we can open the given Android URI to test if permission required error is thrown.
+ * Only relevant for API version 23 and above. + * + * @param context used to access Android APIs, like content resolve, it is your + * activity/fragment/widget. + * @param uri the result URI of image pick. + */ + public static boolean isUriRequiresPermissions(@NonNull Context context, @NonNull Uri uri) { + try { + ContentResolver resolver = context.getContentResolver(); + InputStream stream = resolver.openInputStream(uri); + if (stream != null) { + stream.close(); + } + return false; + } catch (Exception e) { + return true; + } + } + + public static String getImageFileName(@NonNull FileConfiguration config) { + return config.isAutoImageFileName() ? getDefaultImageFileName(config) : config.getImageFileName(); + } + + private static String getDefaultImageFileName(@NonNull FileConfiguration config) { + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmssSS").format(new Date()); + return config.getSuffix().toUpperCase() + "_" + timeStamp + "_"; + } + + private static void log(FileConfiguration conf, String tag, String msg, Throwable tr) { + if (conf.getImageLogCallback() == null) { + Log.e(tag, msg, tr); + } else { + conf.getImageLogCallback().log(tag, msg, tr); + } + } + + private static void log(FileConfiguration conf, String tag, String msg) { + if (conf.getImageLogCallback() == null) { + Log.e(tag, msg); + } else { + conf.getImageLogCallback().log(tag, msg); + } + } + +} diff --git a/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/ImageLogCallback.java b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/ImageLogCallback.java new file mode 100644 index 0000000..e1cc7a6 --- /dev/null +++ b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/ImageLogCallback.java @@ -0,0 +1,8 @@ +package com.devtk.cameralibrary.ImagePicker; + +public interface ImageLogCallback { + + void log(String tag, String msg, Throwable tr); + + void log(String tag, String msg); +} diff --git a/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/ImageSource.java b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/ImageSource.java new file mode 100644 index 0000000..ad7381b --- /dev/null +++ b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/ImageSource.java @@ -0,0 +1,11 @@ +package com.devtk.cameralibrary.ImagePicker; + +public enum ImageSource { + GALLERY, + DOCUMENTS, + CAMERA_IMAGE, + CAMERA_VIDEO; + + private ImageSource() { + } +} diff --git a/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/PickImage.java b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/PickImage.java new file mode 100644 index 0000000..df076ef --- /dev/null +++ b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/PickImage.java @@ -0,0 +1,500 @@ +package com.devtk.cameralibrary.ImagePicker; + +import android.app.Activity; +import android.content.ClipData; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.os.Parcelable; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class PickImage { + + //TODO Callback Type muss noch hinzugefügt werden + + /** + * startActivityForResult requestCode + */ + private final static int PICK_IMAGE_REQUEST = 0; + + /** + * Defaults + */ + private static CharSequence title = ""; + private static boolean includeCamera = false; + private static boolean includeDocuments = false; + private static boolean includeMultipleSelect = false; + private static boolean copyPickedImagesToPublicGallery = true; + + private static File file; + private static FileConfiguration fileConfiguration; + private static Context context; + private static ImageLogCallback imageLogCallback; + + /** + * @param context used to access Android APIs, like content resolve, it is your + * activity/fragment/widget. + */ + public PickImage(Context context) { + this.context = context; + } + + /** + * Configuration Klasse ist unten eingefügt. + * + * @param activity um startActivityForResult aufrufen zu können + * @return eine neue Coniguration entweder mit default Werten oder den Benutzerdaten + */ + public static Configuration activity(Activity activity) { + return new Configuration(activity); + } + + /** + * Diese Methode kann nur aus der Coniguration Klasse aufgerufen werden um zu gewährleisten + * das die default configuration durchgeführt wurde. + * + * @param activity um startActivityForResult aufrufen zu können + */ + private static void start(@NonNull Activity activity) { + try { + activity.startActivityForResult(getPickImageChooserIntent(), PICK_IMAGE_REQUEST); + } catch (IOException io) { + log(activity.getClass().getSimpleName(), io.getMessage(), io); + } + } + + + /** + * Create a chooser intent to select the source to get image from.
+ * The source can be camera's (ACTION_IMAGE_CAPTURE) or gallery's (ACTION_GET_CONTENT).
+ * All possible sources are added to the intent chooser. + *

+ *

+ * activity/fragment/widget. + */ + private static Intent getPickImageChooserIntent() throws IOException { + List allIntents = new ArrayList<>(); + PackageManager packageManager = context.getPackageManager(); + + if (includeCamera) { + List cameraIntents = getCameraIntents(packageManager); + if (cameraIntents != null) { + allIntents.addAll(cameraIntents); + } + } + + List galleryIntents = getGalleryIntents(packageManager, Intent.ACTION_GET_CONTENT); + if (galleryIntents.size() == 0) { + // if no intents found for get-content try pick intent action (Huawei P9). + galleryIntents = getGalleryIntents(packageManager, Intent.ACTION_PICK); + } + allIntents.addAll(galleryIntents); + Intent target; + if (allIntents.isEmpty()) { + target = new Intent(); + } else { + target = allIntents.get(allIntents.size() - 1); + allIntents.remove(allIntents.size() - 1); + } + + // Create a chooser from the main intent + Intent chooserIntent = Intent.createChooser(target, title); + + // Add all other intents + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()])); + + return chooserIntent; + } + + /** + * Get all Camera intents for capturing image using device camera apps. + */ + private static List getCameraIntents(@NonNull PackageManager packageManager) throws IOException { + List allIntents = new ArrayList<>(); + + // Determine Uri of camera image to save. (TempFile) + File imagePath = FileHelper.getCameraTempFile(fileConfiguration); + Uri uri = FileHelper.getUriToFile(fileConfiguration, imagePath); + + Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + List listCam = packageManager.queryIntentActivities(captureIntent, 0); + for (ResolveInfo res : listCam) { + Intent intent = new Intent(captureIntent); + intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); + intent.setPackage(res.activityInfo.packageName); + if (uri != null) { + intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + } + allIntents.add(intent); + } + return allIntents; + } + + /** + * Get all Gallery intents for getting image from one of the apps of the device that handle + * images. + */ + private static List getGalleryIntents( + @NonNull PackageManager packageManager, String action) { + List intents = new ArrayList<>(); + Intent galleryIntent = action == Intent.ACTION_GET_CONTENT ? new Intent(action) : new Intent(action, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + galleryIntent.setType("image/*"); + galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, includeMultipleSelect); + List listGallery = packageManager.queryIntentActivities(galleryIntent, 0); + for (ResolveInfo res : listGallery) { + Intent intent = new Intent(galleryIntent); + intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); + intent.setPackage(res.activityInfo.packageName); + intents.add(intent); + } + + // remove documents intent + if (!includeDocuments) { + for (Intent intent : intents) { + if (intent + .getComponent() + .getClassName() + .equals("com.android.documentsui.DocumentsActivity")) { + intents.remove(intent); + break; + } + } + } + return intents; + } + + /** + * Get URI to image received from capture by camera. + */ + private static Uri getCaptureImageOutputUri() throws IOException { + file = FileHelper.getTempImageDirectory(fileConfiguration); + Uri uri = Uri.fromFile(file); + return uri; + } + + /** + * @return the romovestate + */ + public static boolean deleteFile() { + return FileHelper.removeFile(fileConfiguration, file); + } + + /** + * Get the URI of the selected image from {@link #getPickImageChooserIntent()}.
+ * Will return the correct URI for camera and gallery image. + * + * @param data the returned data of the activity result + */ + @Deprecated + public static Uri getPickImageResultUri(@Nullable Intent data) throws IOException { + boolean isCamera = true; + if (data != null && data.getData() != null) { + String action = data.getAction(); + isCamera = action != null && action.equals(MediaStore.ACTION_IMAGE_CAPTURE); + } + return isCamera || data.getData() == null ? getCaptureImageOutputUri() : data.getData(); + } + + /** + * Logt auf der Console wenn kein ImageLogCallback angegeben wurde. + */ + private static void log(String tag, String msg, Throwable tr) { + if (imageLogCallback == null) { + Log.e(tag, msg, tr); + } else { + imageLogCallback.log(tag, msg, tr); + } + } + + + /** + * Diese Methode wird in der aufrufenden Activity in onActivityResult aufgerufen damit kein + * überladener Code entsteht. + * + * @param requestCode 0 == PICK_IMAGE_REQUEST + * @param resultCode -1 == RESULT_OK, 0 == RESULT_CANCELED + * @param data Result data + * @param activity calling activity + * @param callbacks Interface + */ + public static void handleActivityResult(int requestCode, int resultCode, Intent data, Activity activity, Callbacks callbacks) { + if (requestCode == PICK_IMAGE_REQUEST) { + if (resultCode == Activity.RESULT_OK) { + if (requestCode == PICK_IMAGE_REQUEST && !isPhoto(data)) { + onPictureReturnedFromGallery(data, activity, callbacks); + } else if (isPhoto(data)) { + onPictureReturnedFromCamera(activity, callbacks); + } + } else { + if (requestCode == PICK_IMAGE_REQUEST) { + callbacks.onCanceled(ImageSource.GALLERY, 0); + } else { + + } + } + } + } + + private static boolean isPhoto(Intent data) { + return data == null || data.getData() == null && data.getClipData() == null; + } + + private static void onPictureReturnedFromGallery(Intent data, Activity activity, @NonNull Callbacks callbacks) { + try { + ClipData clipData = data.getClipData(); + List files = new ArrayList(); + if (clipData == null) { + Uri uri = data.getData(); + File file = FileHelper.pickedExistingPicture(fileConfiguration, uri); + files.add(file); + } else { + for (int i = 0; i < clipData.getItemCount(); ++i) { + Uri uri = clipData.getItemAt(i).getUri(); + File file = FileHelper.pickedExistingPicture(fileConfiguration, uri); + files.add(file); + } + } + + // Kopiere das File in den external storrage + if (copyPickedImagesToPublicGallery) { + FileHelper.copyFilesInSeparateThread(fileConfiguration, files); + } + + callbacks.onImagesPicked(files, ImageSource.GALLERY, 0); + } catch (Exception var8) { + var8.printStackTrace(); + callbacks.onImagePickerError(var8, ImageSource.GALLERY, 0); + } + + } + + private static void onPictureReturnedFromCamera(Activity activity, @NonNull Callbacks callbacks) { + try { + List files = new ArrayList(); + File photoFile = FileHelper.getCameraTempFile(fileConfiguration); + if (photoFile == null) { + //TODO exception message + callbacks.onImagePickerError(new Exception("Unable to get the picture returned from camera"), ImageSource.CAMERA_IMAGE, 0); + } + if (photoFile == null) { + Exception e = new IllegalStateException("Unable to get the picture returned from camera"); + callbacks.onImagePickerError(e, ImageSource.CAMERA_IMAGE, 0); + } else { + files.add(photoFile); + // Kopiere das File in den external storrage + if (copyPickedImagesToPublicGallery) { + FileHelper.copyFilesInSeparateThread(fileConfiguration, files); + } + callbacks.onImagesPicked(files, ImageSource.CAMERA_IMAGE, 0); + } + } catch (NullPointerException npe) { + callbacks.onImagePickerError(npe, ImageSource.CAMERA_IMAGE, 0); + } catch (IllegalArgumentException ie) { + callbacks.onImagePickerError(ie, ImageSource.CAMERA_IMAGE, 0); + } catch (IOException io) { + callbacks.onImagePickerError(io, ImageSource.CAMERA_IMAGE, 0); + } catch (Exception e) { + callbacks.onImagePickerError(e, ImageSource.CAMERA_IMAGE, 0); + } + } + + /** + * Prüfe ob genug speicher auf dem internal und dem external storrage vorhanden ist und + * genug Speicher verfügbar ist. + * + * @return + */ + private static boolean checkSpace() { + if (!Storrage.isExternalStorrageReady()) { + return false; + } + int minStorragePercent = 10; + if (freeStorrageInPercent(Storrage.getInternalStorrageSize(), Storrage.getFreeInternalStorrageSize()) < minStorragePercent) { + return false; + } else if (freeStorrageInPercent(Storrage.getExternalStorrageSize(), Storrage.getFreeExternalStorrageSize()) < minStorragePercent) { + return false; + } else { + return true; + } + } + + private static double freeStorrageInPercent(double available, double free) { + return (100 / available * free); + } + + public static CharSequence getTitle() { + return title; + } + + /** + * Hier kann die Default config geändert werden. In der Configuration Klasse wird auch auf die + * + * @FileHelper Configuration zugegriffen. In dieser Klasse kann der chooser gestartet werden. + */ + public static final class Configuration { + private Activity activity; + private FileConfiguration fileConfiguration; + + public Configuration(@NonNull Activity activity) { + setDefaults(); + this.activity = activity; + context = activity; + fileConfiguration = new FileConfiguration(context); + PickImage.fileConfiguration = fileConfiguration; + } + + private void setDefaults() { + PickImage.title = ""; + PickImage.includeCamera = false; + PickImage.includeDocuments = false; + PickImage.includeMultipleSelect = false; + PickImage.copyPickedImagesToPublicGallery = true; + PickImage.file = null; + PickImage.fileConfiguration = null; + PickImage.context = null; + PickImage.imageLogCallback = null; + } + + /** + * Starte das chooser Intent + */ + public void start() { + if (!checkSpace()) { + //TODO string.xml + Toast.makeText(context, "Test not enough space", Toast.LENGTH_LONG).show(); + return; + } + PickImage.start(activity); + } + + /** + * @param title Bootomsheet title + * @return Configuration + */ + public Configuration title(CharSequence title) { + PickImage.title = title; + return this; + } + + public Configuration includeCamera(boolean includeCamera) { + PickImage.includeCamera = includeCamera; + return this; + } + + public Configuration includeDocuments(boolean includeDocuments) { + PickImage.includeDocuments = includeDocuments; + return this; + } + + /** + * @param includeMultipleSelect erlaubt es mehrere Bilder aus der Gallerie auszuwählen. + * @return + */ + public Configuration includeMultipleSelect(boolean includeMultipleSelect) { + PickImage.includeMultipleSelect = includeMultipleSelect; + return this; + } + + /** + * @param copyPickedImagesToPublicGallery erlaubt es die Bilder auf den öffentlichen Ordner zu + * speichern damit andere Apps die Bilder finden können + * @return + */ + public Configuration shouldCopyPickedImagesToPublicGalleryAppFolder(boolean copyPickedImagesToPublicGallery) { + PickImage.copyPickedImagesToPublicGallery = copyPickedImagesToPublicGallery; + fileConfiguration.writeToExternalStorrage(copyPickedImagesToPublicGallery); + return this; + } + + /** + * @param imageLogCallback gibt die Logs an die aufrufende Klasse zurück + * @return + */ + public Configuration logCallback(ImageLogCallback imageLogCallback) { + PickImage.imageLogCallback = imageLogCallback; + fileConfiguration.logCallback(imageLogCallback); + return this; + } + + /** + * Default filePath = appname + * + * @param filePath + * @return + */ + public Configuration filePath(String filePath) { + fileConfiguration.folderPath(filePath); + return this; + } + + /** + * Default imageFilename suffix.toUpperCase() + "_" + timeStamp + "_" + suffix + * + * @param filename der filename kann manuell gewählt werden oder Automatisch erstellt werden + * @return + */ + public Configuration imageFilename(String filename) { + fileConfiguration.imageFileName(filename); + setAutoImageFileName(false); + return this; + } + + /** + * imageFilename auto == suffix.toUpperCase() + "_" + timeStamp + "_" + suffix + * + * @param autoImageFileName + * @return + */ + public Configuration setAutoImageFileName(boolean autoImageFileName) { + fileConfiguration.setAutoImageFileName(autoImageFileName); + return this; + } + + + /** + * defautl environment = DIRECTORY_DCIM + * + * @param environment DIRECTORY_MUSIC + * DIRECTORY_PODCASTS + * DIRECTORY_RINGTONES + * DIRECTORY_ALARMS + * DIRECTORY_NOTIFICATIONS + * DIRECTORY_PICTURES damit gibt es probleme beim auslesen onActivityResult. + * bei manchen devices ist der Zugriff nicht erlaubt. Besser + * DIRECTORY_DCIM wählen + *

+ * DIRECTORY_MOVIES + * DIRECTORY_DOWNLOADS + * DIRECTORY_DCIM + * DIRECTORY_DOCUMENTS + * @return + */ + public Configuration environment(String environment) { + fileConfiguration.environment(environment); + return this; + } + + /** + * default suffix = .jpg + * + * @param suffix z.Bsp. .jpg, .PNG + * @return + */ + public Configuration suffix(String suffix) { + fileConfiguration.suffix(suffix); + return this; + } + } +} diff --git a/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/Storrage.java b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/Storrage.java new file mode 100644 index 0000000..988dc73 --- /dev/null +++ b/cameralibrary/src/main/java/com/devtk/cameralibrary/ImagePicker/Storrage.java @@ -0,0 +1,63 @@ +package com.devtk.cameralibrary.ImagePicker; + +import android.os.Environment; +import android.os.StatFs; + +import java.io.File; + +public class Storrage { + + public static boolean isExternalStorrageReady() { + return isExternalStorageAvailable() && !isExternalStorageReadOnly(); + } + + private static boolean isExternalStorageReadOnly() { + String extStorageState = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) { + return true; + } + return false; + } + + private static boolean isExternalStorageAvailable() { + String extStorageState = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(extStorageState)) { + return true; + } + return false; + } + + public static long getFreeInternalStorrageSize() { + File path = Environment.getDataDirectory(); + return path.getUsableSpace(); + } + + public static long getUsedInternalStorrageSize() { + File path = Environment.getDataDirectory(); + StatFs stat = new StatFs(path.getPath()); + long free_memory = (stat.getBlockCountLong() - stat.getAvailableBlocksLong()) * stat.getBlockSizeLong(); //return value is in bytes + return free_memory; + } + + public static long getInternalStorrageSize() { + File path = Environment.getDataDirectory(); + return path.getTotalSpace(); + } + + public static long getFreeExternalStorrageSize() { + File path = Environment.getExternalStorageDirectory(); + return path.getUsableSpace(); + } + + public static long getUsedExternalStorrageSize() { + File path = Environment.getExternalStorageDirectory(); + StatFs stat = new StatFs(path.getPath()); + long free_memory = (stat.getBlockCountLong() - stat.getAvailableBlocksLong()) * stat.getBlockSizeLong(); //return value is in bytes + return free_memory; + } + + public static long getExternalStorrageSize() { + File path = Environment.getExternalStorageDirectory(); + return path.getTotalSpace(); + } +} diff --git a/cameralibrary/src/main/res/xml/image_path.xml b/cameralibrary/src/main/res/xml/image_path.xml new file mode 100644 index 0000000..a3f7dc9 --- /dev/null +++ b/cameralibrary/src/main/res/xml/image_path.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file