package com.aviadmini.quickimagepick; import android.annotation.SuppressLint; import android.app.Activity; import android.content.ClipData; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; import android.support.v4.app.Fragment; import android.text.TextUtils; import java.io.File; import java.util.ArrayList; /** * QuickImagePick entry point in v2.x * <br><br> * Create a {@link PickRequest} using one of {@code in(*)} methods and use chained calls to set up and launch the pick request * * @author aviadmini * @see <a href="https://github.com/aviadmini/quickimagepick">GitHub repo</a> * @since v2.0.0 */ @SuppressWarnings({"unused", "WeakerAccess"}) public class QiPick { static final String PREFS_REQUEST_TYPE = "qip_req_type"; static final String PREFS_LAST_CAMERA_URI = "qip_last_cam_uri"; static final String PREFS_CAMERA_DIR = "qip_cam_dir"; static final String PREFS_ALLOWED_MIME_TYPE = "qip_allowed_mime_type"; static final String PREFS_ALLOWED_MIME_TYPES_KITKAT = "qip_allowed_mime_types_kitkat"; static final String PREFS_ALLOW_LOCAL_CONTENT_ONLY = "qip_local_content_only"; static final int REQ_CAMERA = 46211; static final int REQ_GALLERY = 46212; static final int REQ_DOCUMENTS = 46213; static final int REQ_MULTIPLE = 46214; public static final String ERR_CAMERA_NULL_RESULT = "Camera returned bad/null data"; public static final String ERR_CAMERA_CANNOT_WRITE_OUTPUT = "App cannot write to specified camera output directory"; public static final String ERR_GALLERY_NULL_RESULT = "Gallery returned bad/null data"; public static final String ERR_DOCS_NULL_RESULT = "Documents returned bad/null data"; public static final String MIME_TYPE_IMAGES_ALL = "image/*"; public static final String MIME_TYPE_IMAGE_BMP = "image/bmp"; public static final String MIME_TYPE_IMAGE_GIF = "image/gif"; public static final String MIME_TYPE_IMAGE_JPEG = "image/jpeg"; public static final String MIME_TYPE_IMAGE_PNG = "image/png"; public static final String MIME_TYPE_IMAGE_WEBP = "image/webp"; static final boolean API_18 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; static final boolean API_19 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; static final boolean API_23 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; private QiPick() {} /** * @param pActivity Activity to which pick result will be returned * @return PickRequest to set up pick request and trigger it */ public static PickRequest in(@NonNull final Activity pActivity) { return new PickRequest(pActivity); } /** * @param pFragment Support fragment to which pick result will be returned * @return PickRequest to set up pick request and trigger it */ public static PickRequest in(@NonNull final Fragment pFragment) { return new PickRequest(pFragment); } /** * @param pFragment Fragment to which pick result will be returned * @return PickRequest to set up pick request and trigger it */ @RequiresApi(Build.VERSION_CODES.HONEYCOMB) public static PickRequest in(@NonNull final android.app.Fragment pFragment) { return new PickRequest(pFragment); } // ==== RESULT HANDLING ==== // /** * Use this in {@code onActivityResult(...)} of Activity or Fragment to retrieve image {@link Uri} * * @param pFragment support fragment * @param pRequestCode request code from {@code onActivityResult(...)} parameter * @param pResultCode result code from {@code onActivityResult(...)} parameter * @param pData Intent from {@code onActivityResult(...)} parameter * @param pCallback result callback * @return true if result was accepted by QuickImagePick */ public static boolean handleActivityResult(@NonNull final Fragment pFragment, final int pRequestCode, final int pResultCode, @Nullable final Intent pData, @NonNull final PickCallback pCallback) { return handleActivityResult(pFragment.getContext(), pRequestCode, pResultCode, pData, pCallback); } /** * Use this in {@code onActivityResult(...)} of Activity or Fragment to retrieve image {@link Uri} * * @param pFragment fragment * @param pRequestCode request code from {@code onActivityResult(...)} parameter * @param pResultCode result code from {@code onActivityResult(...)} parameter * @param pData Intent from {@code onActivityResult(...)} parameter * @param pCallback result callback * @return true if result was accepted by QuickImagePick */ @SuppressLint("NewApi") public static boolean handleActivityResult(@NonNull final android.app.Fragment pFragment, final int pRequestCode, final int pResultCode, @Nullable final Intent pData, @NonNull final PickCallback pCallback) { return handleActivityResult(API_23 ? pFragment.getContext() : pFragment.getActivity(), pRequestCode, pResultCode, pData, pCallback); } /** * Use this in {@code onActivityResult(...)} of Activity or Fragment to retrieve image {@link Uri} * <br> * Note: for Fragments it's advised to use Fragment-specific overloads of this method * * @param pContext app {@link Context} * @param pRequestCode request code from {@code onActivityResult(...)} parameter * @param pResultCode result code from {@code onActivityResult(...)} parameter * @param pData Intent from {@code onActivityResult(...)} parameter * @param pCallback result callback * @return true if result was accepted by QuickImagePick * @see #handleActivityResult(Fragment, int, int, Intent, PickCallback) * @see #handleActivityResult(android.app.Fragment, int, int, Intent, PickCallback) */ @SuppressLint("NewApi") public static boolean handleActivityResult(@NonNull final Context pContext, final int pRequestCode, final int pResultCode, @Nullable final Intent pData, @NonNull final PickCallback pCallback) { if (pRequestCode != REQ_CAMERA && pRequestCode != REQ_GALLERY && pRequestCode != REQ_DOCUMENTS && pRequestCode != REQ_MULTIPLE) { return false; } final int requestType = PreferenceManager.getDefaultSharedPreferences(pContext) .getInt(PREFS_REQUEST_TYPE, 0); if (pResultCode == Activity.RESULT_OK) { if (pRequestCode == REQ_DOCUMENTS) { handleResultFromDocuments(requestType, pCallback, pData); } else if (pRequestCode == REQ_GALLERY) { handleResultFromGallery(requestType, pCallback, pData); } else if (pRequestCode == REQ_CAMERA) { handleResultFromCamera(pContext, requestType, pCallback, pData); } else if (pData == null || pData.getData() == null && API_18 && pData.getClipData() == null) { handleResultFromCamera(pContext, requestType, pCallback, pData); } else { handleResultFromDocuments(requestType, pCallback, pData); } final String lastCameraUriString = PreferenceManager.getDefaultSharedPreferences(pContext) .getString(PREFS_LAST_CAMERA_URI, null); final Uri lastCameraUri = TextUtils.isEmpty(lastCameraUriString) ? null : Uri.parse(lastCameraUriString); if (lastCameraUri != null) { pContext.getApplicationContext() .revokeUriPermission(lastCameraUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } } else { if (pRequestCode == REQ_DOCUMENTS) { pCallback.onCancel(PickSource.DOCUMENTS, requestType); } else if (pRequestCode == REQ_GALLERY) { pCallback.onCancel(PickSource.GALLERY, requestType); } else if (pRequestCode == REQ_CAMERA) { pCallback.onCancel(PickSource.CAMERA, requestType); deleteLastCameraPic(pContext); } else { if (pData == null || pData.getData() == null && API_18 && pData.getClipData() == null) { pCallback.onCancel(PickSource.CAMERA, requestType); deleteLastCameraPic(pContext); } else { pCallback.onCancel(PickSource.DOCUMENTS, requestType); } } } return true; } private static void handleResultFromCamera(@NonNull final Context pContext, final int pRequestType, @NonNull final PickCallback pCallback, @Nullable final Intent pData) { final File cameraPicsDir = getCameraPicsDirectory(pContext); if (cameraPicsDir == null || !cameraPicsDir.canWrite()) { pCallback.onError(PickSource.CAMERA, pRequestType, ERR_CAMERA_CANNOT_WRITE_OUTPUT); return; } final Uri pictureUri = getLastCameraUri(pContext); if (pictureUri == null) { pCallback.onError(PickSource.CAMERA, pRequestType, ERR_CAMERA_NULL_RESULT); } else { pCallback.onImagePicked(PickSource.CAMERA, pRequestType, pictureUri); } } private static void handleResultFromGallery(final int pRequestType, @NonNull final PickCallback pCallback, @Nullable final Intent pData) { final Uri pictureUri = pData == null ? null : pData.getData(); if (pictureUri == null) { pCallback.onError(PickSource.GALLERY, pRequestType, ERR_GALLERY_NULL_RESULT); } else { pCallback.onImagePicked(PickSource.GALLERY, pRequestType, pictureUri); } } @SuppressLint("NewApi") private static void handleResultFromDocuments(final int pRequestType, @NonNull final PickCallback pCallback, @Nullable final Intent pData) { final Uri pictureUri = pData == null ? null : pData.getData(); if (pictureUri == null) { final ClipData clipData = API_18 ? pData != null ? pData.getClipData() : null : null; if (clipData != null) { final ArrayList<Uri> uris = new ArrayList<>(); for (int i = 0; i < clipData.getItemCount(); i++) { final ClipData.Item item = clipData.getItemAt(i); final Uri uri = item.getUri(); if (uri != null) { uris.add(uri); } } if (uris.isEmpty()) { pCallback.onError(PickSource.DOCUMENTS, pRequestType, ERR_DOCS_NULL_RESULT); } else { pCallback.onMultipleImagesPicked(pRequestType, uris); } } else { pCallback.onError(PickSource.DOCUMENTS, pRequestType, ERR_DOCS_NULL_RESULT); } } else { pCallback.onImagePicked(PickSource.DOCUMENTS, pRequestType, pictureUri); } } // ==== CAMERA DIR ==== // /** * @param pContext app {@link Context} * @return directory where pictures taken by camera apps will be saved or null if an error occurs. * By default it's a pictures directory on external storage. */ public static File getCameraPicsDirectory(@NonNull final Context pContext) { final String camDirPath = PreferenceManager.getDefaultSharedPreferences(pContext) .getString(QiPick.PREFS_CAMERA_DIR, null); final File dir = camDirPath == null ? pContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES) : new File(camDirPath); if (dir != null) { //noinspection ConstantConditions,ResultOfMethodCallIgnored dir.mkdirs(); } return dir; } // ==== LAST CAM PIC ==== // /** * @param pContext app {@link Context} * @return Uri of last camera pic. Not necessarily valid content */ public static Uri getLastCameraUri(@NonNull final Context pContext) { final String uriString = PreferenceManager.getDefaultSharedPreferences(pContext) .getString(QiPick.PREFS_LAST_CAMERA_URI, null); return uriString == null ? null : Uri.parse(uriString); } /** * @param pContext app {@link Context} * @return number of rows deleted from content provider */ public static int deleteLastCameraPic(@NonNull final Context pContext) { final Uri uri = getLastCameraUri(pContext); if (uri != null) { return UriUtils.deleteContent(pContext, uri); } return 0; } // ==== // }