diff --git a/build.gradle b/build.gradle index 38bdccd..1c3b4a0 100644 --- a/build.gradle +++ b/build.gradle @@ -20,8 +20,8 @@ ext { configuration = [ app_name : "ImagePicker", packageName : "com.mvc.imagepicker", - compileVersion : 24, - buildToolsVersion : "23.0.3", + compileVersion : 25, + buildToolsVersion : "25.0.3", minSdk : 14, targetSdk : 24 ] @@ -36,7 +36,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.3' + classpath 'com.android.tools.build:gradle:2.3.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 84fb4fd..b3219c2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Sep 08 12:02:41 CEST 2016 +#Fri Jun 30 14:03:37 MSK 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/library/src/main/java/com/mvc/imagepicker/ImagePicker.java b/library/src/main/java/com/mvc/imagepicker/ImagePicker.java index 0bb19ba..66d8a50 100644 --- a/library/src/main/java/com/mvc/imagepicker/ImagePicker.java +++ b/library/src/main/java/com/mvc/imagepicker/ImagePicker.java @@ -29,6 +29,7 @@ import android.net.Uri; import android.os.Parcelable; import android.provider.MediaStore; +import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; import android.util.Log; @@ -49,7 +50,8 @@ */ public final class ImagePicker { - public static final int PICK_IMAGE_REQUEST_CODE = 234; // the number doesn't matter + private static final int DEFAULT_REQUEST_CODE = 234; + private static final int DEFAULT_MIN_WIDTH_QUALITY = 400; // min pixels private static final int DEFAULT_MIN_HEIGHT_QUALITY = 400; // min pixels private static final String TAG = ImagePicker.class.getSimpleName(); @@ -58,29 +60,71 @@ public final class ImagePicker { private static int minWidthQuality = DEFAULT_MIN_WIDTH_QUALITY; private static int minHeightQuality = DEFAULT_MIN_HEIGHT_QUALITY; + private static String mChooserTitle; + private static int mPickImageRequestCode = DEFAULT_REQUEST_CODE; + private static boolean mGalleryOnly = false; + private ImagePicker() { // not called } /** - * Launch a dialog to pick an image from camera/gallery apps. + * Launch a dialog to pick an image from camera/gallery apps with custom request code. + * + * @param activity which will launch the dialog. + * @param requestCode request code that will be returned in result. + */ + public static void pickImage(Activity activity, int requestCode) { + pickImage(activity, activity.getString(R.string.pick_image_intent_text), requestCode, false); + } + + /** + * Launch a dialog to pick an image from camera/gallery apps with custom request code. * * @param activity which will launch the dialog. */ public static void pickImage(Activity activity) { - String chooserTitle = activity.getString(R.string.pick_image_intent_text); - pickImage(activity, chooserTitle); + pickImage(activity, activity.getString(R.string.pick_image_intent_text), DEFAULT_REQUEST_CODE, false); } /** - * Launch a dialog to pick an image from camera/gallery apps. + * Launch a dialog to pick an image from camera/gallery apps with custom request code. * - * @param fragment which will launch the dialog and will get the result in - * onActivityResult() + * @param fragment which will launch the dialog. + * @param requestCode request code that will be returned in result. + */ + public static void pickImage(Fragment fragment, int requestCode) { + pickImage(fragment, fragment.getString(R.string.pick_image_intent_text), requestCode, false); + } + + /** + * Launch a dialog to pick an image from camera/gallery apps with custom request code. + * + * @param fragment which will launch the dialog. */ public static void pickImage(Fragment fragment) { - String chooserTitle = fragment.getString(R.string.pick_image_intent_text); - pickImage(fragment, chooserTitle); + pickImage(fragment, fragment.getString(R.string.pick_image_intent_text), DEFAULT_REQUEST_CODE, false); + } + + /** + * Launch a dialog to pick an image from gallery apps only with custom request code. + * + * @param activity which will launch the dialog. + * @param requestCode request code that will be returned in result. + */ + public static void pickImageGalleryOnly(Activity activity, int requestCode) { + pickImage(activity, activity.getString(R.string.pick_image_intent_text), requestCode, true); + + } + + /** + * Launch a dialog to pick an image from gallery apps only with custom request code. + * + * @param fragment which will launch the dialog. + * @param requestCode request code that will be returned in result. + */ + public static void pickImageGalleryOnly(Fragment fragment, int requestCode) { + pickImage(fragment, fragment.getString(R.string.pick_image_intent_text), requestCode, true); } /** @@ -90,8 +134,7 @@ public static void pickImage(Fragment fragment) { * @param chooserTitle will appear on the picker dialog. */ public static void pickImage(Activity activity, String chooserTitle) { - Intent chooseImageIntent = getPickImageIntent(activity, chooserTitle); - activity.startActivityForResult(chooseImageIntent, PICK_IMAGE_REQUEST_CODE); + pickImage(activity, chooserTitle, DEFAULT_REQUEST_CODE, false); } /** @@ -102,8 +145,48 @@ public static void pickImage(Activity activity, String chooserTitle) { * @param chooserTitle will appear on the picker dialog. */ public static void pickImage(Fragment fragment, String chooserTitle) { - Intent chooseImageIntent = getPickImageIntent(fragment.getContext(), chooserTitle); - fragment.startActivityForResult(chooseImageIntent, PICK_IMAGE_REQUEST_CODE); + pickImage(fragment, chooserTitle, DEFAULT_REQUEST_CODE, false); + } + + /** + * Launch a dialog to pick an image from camera/gallery apps. + * + * @param fragment which will launch the dialog and will get the result in + * onActivityResult() + * @param chooserTitle will appear on the picker dialog. + * @param requestCode request code that will be returned in result. + */ + public static void pickImage(Fragment fragment, String chooserTitle, + int requestCode, boolean galleryOnly) { + mGalleryOnly = galleryOnly; + mPickImageRequestCode = requestCode; + mChooserTitle = chooserTitle; + startChooser(fragment); + } + + /** + * Launch a dialog to pick an image from camera/gallery apps. + * + * @param activity which will launch the dialog and will get the result in + * onActivityResult() + * @param chooserTitle will appear on the picker dialog. + */ + public static void pickImage(Activity activity, String chooserTitle, + int requestCode, boolean galleryOnly) { + mGalleryOnly = galleryOnly; + mPickImageRequestCode = requestCode; + mChooserTitle = chooserTitle; + startChooser(activity); + } + + private static void startChooser(Fragment fragmentContext) { + Intent chooseImageIntent = getPickImageIntent(fragmentContext.getContext(), mChooserTitle); + fragmentContext.startActivityForResult(chooseImageIntent, mPickImageRequestCode); + } + + private static void startChooser(Activity activityContext) { + Intent chooseImageIntent = getPickImageIntent(activityContext, mChooserTitle); + activityContext.startActivityForResult(chooseImageIntent, mPickImageRequestCode); } /** @@ -121,16 +204,20 @@ public static Intent getPickImageIntent(Context context, String chooserTitle) { android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intentList = addIntentsToList(context, intentList, pickIntent); - // Camera action will fail if the app does not have permission, check before adding intent. - // We only need to add the camera intent if the app does not use the CAMERA permission - // in the androidmanifest.xml - // Or if the user has granted access to the camera. - // See https://developer.android.com/reference/android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE - if (!appManifestContainsPermission(context, Manifest.permission.CAMERA) || hasCameraAccess(context)) { - Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - takePhotoIntent.putExtra("return-data", true); - takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTemporalFile(context))); - intentList = addIntentsToList(context, intentList, takePhotoIntent); + // Check is we want gallery apps only + if (!mGalleryOnly) { + // Camera action will fail if the app does not have permission, check before adding intent. + // We only need to add the camera intent if the app does not use the CAMERA permission + // in the androidmanifest.xml + // Or if the user has granted access to the camera. + // See https://developer.android.com/reference/android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE + if (!appManifestContainsPermission(context, Manifest.permission.CAMERA) || hasCameraAccess(context)) { + Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + takePhotoIntent.putExtra("return-data", true); + takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, + Uri.fromFile(ImageUtils.getTemporalFile(context, String.valueOf(mPickImageRequestCode)))); + intentList = addIntentsToList(context, intentList, takePhotoIntent); + } } if (intentList.size() > 0) { @@ -202,12 +289,13 @@ private static boolean appManifestContainsPermission(Context context, String per * @param imageReturnedIntent returned intent where is the image data. * @return image. */ + @Nullable public static Bitmap getImageFromResult(Context context, int requestCode, int resultCode, Intent imageReturnedIntent) { Log.i(TAG, "getImageFromResult() called with: " + "resultCode = [" + resultCode + "]"); Bitmap bm = null; - if (resultCode == Activity.RESULT_OK && requestCode == PICK_IMAGE_REQUEST_CODE) { - File imageFile = getTemporalFile(context); + if (resultCode == Activity.RESULT_OK && requestCode == mPickImageRequestCode) { + File imageFile = ImageUtils.getTemporalFile(context, String.valueOf(mPickImageRequestCode)); Uri selectedImage; boolean isCamera = (imageReturnedIntent == null || imageReturnedIntent.getData() == null @@ -226,6 +314,66 @@ public static Bitmap getImageFromResult(Context context, int requestCode, int re return bm; } + /** + * Called after launching the picker with the same values of Activity.getImageFromResult + * in order to resolve the result and get the image path. + * + * @param context context. + * @param requestCode used to identify the pick image action. + * @param resultCode -1 means the result is OK. + * @param imageReturnedIntent returned intent where is the image data. + * @return path to the saved image. + */ + @Nullable + public static String getImagePathFromResult(Context context, int requestCode, int resultCode, + Intent imageReturnedIntent) { + Log.i(TAG, "getImagePathFromResult() called with: " + "resultCode = [" + resultCode + "]"); + Uri selectedImage = null; + if (resultCode == Activity.RESULT_OK && requestCode == mPickImageRequestCode) { + File imageFile = ImageUtils.getTemporalFile(context, String.valueOf(mPickImageRequestCode)); + boolean isCamera = (imageReturnedIntent == null + || imageReturnedIntent.getData() == null + || imageReturnedIntent.getData().toString().contains(imageFile.toString())); + if (isCamera) { + return imageFile.getAbsolutePath(); + } else { + selectedImage = imageReturnedIntent.getData(); + } + Log.i(TAG, "selectedImage: " + selectedImage); + } + if (selectedImage == null) { + return null; + } + return getFilePathFromUri(context, selectedImage); + } + + /** + * Get stream, save the picture to the temp file and return path. + * + * @param context context + * @param uri uri of the incoming file + * @return path to the saved image. + */ + private static String getFilePathFromUri(Context context, Uri uri) { + InputStream is = null; + if (uri.getAuthority() != null) { + try { + is = context.getContentResolver().openInputStream(uri); + Bitmap bmp = BitmapFactory.decodeStream(is); + return ImageUtils.savePicture(context, bmp, String.valueOf(uri.getPath().hashCode())); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + } + /** * Called after launching the picker with the same values of Activity.getImageFromResult * in order to resolve the result and get the input stream for the image. @@ -239,8 +387,8 @@ public static Bitmap getImageFromResult(Context context, int requestCode, int re public static InputStream getInputStreamFromResult(Context context, int requestCode, int resultCode, Intent imageReturnedIntent) { Log.i(TAG, "getFileFromResult() called with: " + "resultCode = [" + resultCode + "]"); - if (resultCode == Activity.RESULT_OK && requestCode == PICK_IMAGE_REQUEST_CODE) { - File imageFile = getTemporalFile(context); + if (resultCode == Activity.RESULT_OK && requestCode == mPickImageRequestCode) { + File imageFile = ImageUtils.getTemporalFile(context, String.valueOf(mPickImageRequestCode)); Uri selectedImage; boolean isCamera = (imageReturnedIntent == null || imageReturnedIntent.getData() == null @@ -268,10 +416,6 @@ public static InputStream getInputStreamFromResult(Context context, int requestC return null; } - private static File getTemporalFile(Context context) { - return new File(context.getExternalCacheDir(), TEMP_IMAGE_NAME); - } - /** * Loads a bitmap and avoids using too much memory loading big images (e.g.: 2560*1920) */ diff --git a/library/src/main/java/com/mvc/imagepicker/ImageUtils.java b/library/src/main/java/com/mvc/imagepicker/ImageUtils.java new file mode 100644 index 0000000..9ed6e03 --- /dev/null +++ b/library/src/main/java/com/mvc/imagepicker/ImageUtils.java @@ -0,0 +1,51 @@ +package com.mvc.imagepicker; + +import android.content.Context; +import android.graphics.Bitmap; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Created by Anatol on 11/12/2016. + */ + +public final class ImageUtils { + + private static final String BASE_IMAGE_NAME = "i_prefix_"; + + private ImageUtils() { + } + + public static String savePicture(Context context, Bitmap bitmap, String imageSuffix) { + File savedImage = getTemporalFile(context, imageSuffix + ".jpeg"); + FileOutputStream fos = null; + if (savedImage.exists()) { + savedImage.delete(); + } + try { + fos = new FileOutputStream(savedImage.getPath()); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos); + } catch (java.io.IOException e) { + e.printStackTrace(); + } finally { + if (!bitmap.isRecycled()) { + bitmap.recycle(); + } + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + return savedImage.getAbsolutePath(); + } + + public static File getTemporalFile(Context context, String payload) { + return new File(context.getExternalCacheDir(), BASE_IMAGE_NAME + payload); + } +} diff --git a/sample/build.gradle b/sample/build.gradle index 6861210..c30f158 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -62,11 +62,13 @@ android { } } } + buildToolsVersion '25.0.0' } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' + compile 'com.squareup.picasso:picasso:2.5.2' compile "com.android.support:appcompat-v7:${libs.supportVersion}" compile project(':library') } diff --git a/sample/src/main/java/com/mvc/imagepicker/sample/MainFragment.java b/sample/src/main/java/com/mvc/imagepicker/sample/MainFragment.java index 04f12bd..1711b81 100644 --- a/sample/src/main/java/com/mvc/imagepicker/sample/MainFragment.java +++ b/sample/src/main/java/com/mvc/imagepicker/sample/MainFragment.java @@ -17,8 +17,10 @@ package com.mvc.imagepicker.sample; import android.content.Intent; +import android.content.SharedPreferences; import android.graphics.Bitmap; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; @@ -28,7 +30,9 @@ import android.widget.TextView; import com.mvc.imagepicker.ImagePicker; +import com.squareup.picasso.Picasso; +import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -39,7 +43,14 @@ public class MainFragment extends Fragment { - private ImageView imageView; + public static final String CACHED_IMG_KEY = "img_key"; + + public static final int SECOND_PIC_REQ = 1313; + public static final int GALLERY_ONLY_REQ = 1212; + + private ImageView imageView1; + private ImageView imageView2; + private ImageView imageViewGalleryOnly; private TextView textView; @@ -53,22 +64,61 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_main, container, false); - imageView = (ImageView) v.findViewById(R.id.image_view); + imageView1 = (ImageView) v.findViewById(R.id.image_view_1); + imageView2 = (ImageView) v.findViewById(R.id.image_view_2); + imageViewGalleryOnly = (ImageView) v.findViewById(R.id.image_view_gallery_only); textView = (TextView) v.findViewById(R.id.image_stream_indicator); - imageView.setOnClickListener(new View.OnClickListener() { + imageView1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ImagePicker.pickImage(MainFragment.this, "Select your image:"); } }); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + String path = prefs.getString(CACHED_IMG_KEY, ""); + File cached = new File(path); + if (cached.exists()) { + Picasso.with(getActivity()).load(cached).into(imageView2); + } + imageView2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ImagePicker.pickImage(MainFragment.this, SECOND_PIC_REQ); + } + }); + imageViewGalleryOnly.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ImagePicker.pickImageGalleryOnly(MainFragment.this, GALLERY_ONLY_REQ); + } + }); return v; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - Bitmap bitmap = ImagePicker.getImageFromResult(getActivity(), requestCode, resultCode, data); - if (bitmap != null) { - imageView.setImageBitmap(bitmap); + + switch (requestCode) { + case SECOND_PIC_REQ: + String imagePathFromResult = ImagePicker.getImagePathFromResult(getActivity(), + requestCode, resultCode, data); + if (imagePathFromResult != null) { + String path = "file:///" + imagePathFromResult; + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + prefs.edit().putString(CACHED_IMG_KEY, imagePathFromResult).apply(); + Picasso.with(getActivity()).load(path).into(imageView2); + } + break; + case GALLERY_ONLY_REQ: + String pathFromGallery = "file:///" + ImagePicker.getImagePathFromResult(getActivity(), requestCode, + resultCode, data); + Picasso.with(getActivity()).load(pathFromGallery).into(imageViewGalleryOnly); + break; + default: + Bitmap bitmap = ImagePicker.getImageFromResult(getActivity(), requestCode, resultCode, data); + if (bitmap != null) { + imageView1.setImageBitmap(bitmap); + } } InputStream is = ImagePicker.getInputStreamFromResult(getActivity(), requestCode, resultCode, data); if (is != null) { diff --git a/sample/src/main/res/layout/fragment_main.xml b/sample/src/main/res/layout/fragment_main.xml index 39d848b..a9b38d8 100644 --- a/sample/src/main/res/layout/fragment_main.xml +++ b/sample/src/main/res/layout/fragment_main.xml @@ -31,7 +31,21 @@ android:layout_margin="@dimen/picker_text_margin"/> + + + +