Skip to content

Commit

Permalink
Fixed gallery image pick issue
Browse files Browse the repository at this point in the history
- Sample app made compatible with Android Kitkat 4.4+ (API 19)
- Fixed Uri to File Conversion issue #8 - (Special Thanks to squeeish)
- Added Support for Inline Activity Result(Special Thanks to soareseneves)
Fixed App crash issue reported here #6.
  • Loading branch information
Dhaval2404 committed Jul 24, 2019
1 parent 5800fef commit c398730
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 47 deletions.
13 changes: 10 additions & 3 deletions imagepicker-support/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ android {
defaultConfig {
minSdkVersion 19
targetSdkVersion 28
versionCode 2
versionName "1.1"
versionCode 4
versionName "1.3"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
Expand All @@ -27,6 +29,11 @@ android {
main.java.srcDirs += 'src/main/kotlin'
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

}

dependencies {
Expand Down Expand Up @@ -57,7 +64,7 @@ ext {
siteUrl = 'https://github.com/Dhaval2404/ImagePicker/'
gitUrl = 'https://github.com/Dhaval2404/ImagePicker.git'

libraryVersion = '1.1'
libraryVersion = '1.3'
//If you are uploading new library try : gradlew install
//If you are updating existing library then execute: gradlew bintrayUpload
//In both the case don't forgot to put bintray credentials in local.properties file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import java.io.File
* @version 1.0
* @since 04 January 2019
*/
class ImagePicker {
open class ImagePicker {

companion object {
// Default Request Code to Pick Image
Expand Down Expand Up @@ -125,18 +125,20 @@ class ImagePicker {
}

/**
* Only Capture image using Camera
* Only Capture image using Camera.
*/
// @Deprecated("Please use provider(ImageProvider.CAMERA) instead")
fun cameraOnly(): Builder {
imageProvider = ImageProvider.CAMERA
this.imageProvider = ImageProvider.CAMERA
return this
}

/**
* Only Pick image from gallery
* Only Pick image from gallery.
*/
// @Deprecated("Please use provider(ImageProvider.GALLERY) instead")
fun galleryOnly(): Builder {
imageProvider = ImageProvider.GALLERY
this.imageProvider = ImageProvider.GALLERY
return this
}

Expand Down Expand Up @@ -284,12 +286,8 @@ class ImagePicker {
}
} catch (e: Exception) {
if (e is ClassNotFoundException) {
Toast.makeText(
if (fragment != null) fragment!!.context else activity,
"InlineActivityResult library not installed falling back to default method, please install " +
"it from https://github.com/florent37/InlineActivityResult if you want to get inline activity results.",
Toast.LENGTH_LONG
).show()
Toast.makeText(if (fragment != null) fragment!!.context else activity, "InlineActivityResult library not installed falling back to default method, please install " +
"it from https://github.com/florent37/InlineActivityResult if you want to get inline activity results.", Toast.LENGTH_LONG).show()
startActivity(REQUEST_CODE)
}
}
Expand All @@ -308,4 +306,4 @@ class ImagePicker {
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.support.v4.app.FragmentActivity
import android.util.Log
import com.github.dhaval2404.imagepicker.constant.ImageProvider
import com.github.dhaval2404.imagepicker.provider.CameraProvider
import com.github.dhaval2404.imagepicker.provider.CompressionProvider
Expand Down Expand Up @@ -53,8 +54,8 @@ class ImagePickerActivity : FragmentActivity() {
mCropProvider = CropProvider(this)
mCompressionProvider = CompressionProvider(this)

val bundle = intent.extras!!
val provider = bundle.getSerializable(ImagePicker.EXTRA_IMAGE_PROVIDER) as ImageProvider
val bundle = intent?.extras
val provider = bundle?.getSerializable(ImagePicker.EXTRA_IMAGE_PROVIDER) as ImageProvider?

// Create provider object and start process
when (provider) {
Expand All @@ -66,6 +67,11 @@ class ImagePickerActivity : FragmentActivity() {
mCameraProvider = CameraProvider(this)
mCameraProvider?.startIntent()
}
else->{
Log.e(TAG, "Image provider can not be null")
//Something went Wrong! This case should never happen
setError(getString(R.string.error_task_cancelled))
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,23 +183,23 @@ class CompressionProvider(activity: ImagePickerActivity) : BaseProvider(activity
* Image Resolution will be reduce with below parameters.
*
*/
private fun resolutionList(): List<Array<Int>> {
return listOf<Array<Int>>(
arrayOf(2448, 3264), // 8.0 Megapixel
arrayOf(2008, 3032), // 6.0 Megapixel
arrayOf(1944, 2580), // 5.0 Megapixel
arrayOf(1680, 2240), // 4.0 Megapixel
arrayOf(1536, 2048), // 3.0 Megapixel
arrayOf(1200, 1600), // 2.0 Megapixel
arrayOf(1024, 1392), // 1.3 Megapixel
arrayOf(960, 1280), // 1.0 Megapixel
arrayOf(768, 1024), // 0.7 Megapixel
arrayOf(600, 800), // 0.4 Megapixel
arrayOf(480, 640), // 0.3 Megapixel
arrayOf(240, 320), // 0.15 Megapixel
arrayOf(120, 160), // 0.08 Megapixel
arrayOf(60, 80), // 0.04 Megapixel
arrayOf(30, 40) // 0.02 Megapixel
private fun resolutionList(): List<IntArray> {
return listOf(
intArrayOf(2448, 3264), // 8.0 Megapixel
intArrayOf(2008, 3032), // 6.0 Megapixel
intArrayOf(1944, 2580), // 5.0 Megapixel
intArrayOf(1680, 2240), // 4.0 Megapixel
intArrayOf(1536, 2048), // 3.0 Megapixel
intArrayOf(1200, 1600), // 2.0 Megapixel
intArrayOf(1024, 1392), // 1.3 Megapixel
intArrayOf(960, 1280), // 1.0 Megapixel
intArrayOf(768, 1024), // 0.7 Megapixel
intArrayOf(600, 800), // 0.4 Megapixel
intArrayOf(480, 640), // 0.3 Megapixel
intArrayOf(240, 320), // 0.15 Megapixel
intArrayOf(120, 160), // 0.08 Megapixel
intArrayOf(60, 80), // 0.04 Megapixel
intArrayOf(30, 40) // 0.02 Megapixel
)
}

Expand All @@ -215,10 +215,10 @@ class CompressionProvider(activity: ImagePickerActivity) : BaseProvider(activity
* @param file File to get Image Size
* @return Int Array, Index 0 has width and Index 1 has height
*/
private fun getImageSize(file: File): Array<Int> {
private fun getImageSize(file: File): IntArray {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, options)
return arrayOf(options.outWidth, options.outHeight)
return intArrayOf(options.outWidth, options.outHeight)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import android.content.Intent
import android.support.v4.app.ActivityCompat.requestPermissions
import com.github.dhaval2404.imagepicker.ImagePickerActivity
import com.github.dhaval2404.imagepicker.R
import com.github.dhaval2404.imagepicker.util.FileUriUtils
import com.github.dhaval2404.imagepicker.util.IntentUtils
import com.github.dhaval2404.imagepicker.util.PermissionUtil
import com.yalantis.ucrop.util.FileUtils
import java.io.File

/**
Expand Down Expand Up @@ -99,7 +99,7 @@ class GalleryProvider(activity: ImagePickerActivity) : BaseProvider(activity) {
private fun handleResult(data: Intent?) {
val uri = data?.data
if (uri != null) {
val filePath: String? = FileUtils.getPath(activity, uri)
val filePath: String? = FileUriUtils.getRealPath(activity, uri)
if (!filePath.isNullOrEmpty()) {
activity.setImage(File(filePath))
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.github.dhaval2404.imagepicker.util

import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import java.io.File

/**
* https://gist.github.com/HBiSoft/15899990b8cd0723c3a894c1636550a8
*
* This class acts as a drop in replacement for uCrop FileUtils class
*/

object FileUriUtils {

fun getRealPath(context: Context, uri: Uri): String? {

val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT

// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]

// This is for checking Main Memory
return if ("primary".equals(type, ignoreCase = true)) {
if (split.size > 1) {
Environment.getExternalStorageDirectory().toString() + "/" + split[1]
} else {
Environment.getExternalStorageDirectory().toString() + "/"
}
// This is for checking SD Card
} else {
val path = "storage" + "/" + docId.replace(":", "/")
if(File(path).exists()){
path
}else{
"/storage/sdcard/"+split[1];
}
}

} else if (isDownloadsDocument(uri)) {
val fileName = getFilePath(context, uri)
if (fileName != null) {
return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
}

val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)
)
return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]

var contentUri: Uri? = null
if ("image" == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}

val selection = "_id=?"
val selectionArgs = arrayOf(split[1])

return getDataColumn(context, contentUri, selection, selectionArgs)
}// MediaProvider
// DownloadsProvider
} else if ("content".equals(uri.scheme!!, ignoreCase = true)) {

// Return the remote address
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null)

} else if ("file".equals(uri.scheme!!, ignoreCase = true)) {
return uri.path
}// File
// MediaStore (and general)

return null
}

private fun getDataColumn(
context: Context, uri: Uri?, selection: String?,
selectionArgs: Array<String>?
): String? {

var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)

try {
cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(index)
}
} finally {
cursor?.close()
}
return null
}


private fun getFilePath(context: Context, uri: Uri): String? {

var cursor: Cursor? = null
val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)

try {
cursor = context.contentResolver.query(uri, projection, null, null, null)
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)
return cursor.getString(index)
}
} finally {
cursor?.close()
}
return null
}

/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}

/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}

/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}

/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
private fun isGooglePhotosUri(uri: Uri): Boolean {
return "com.google.android.apps.photos.content" == uri.authority
}
}
11 changes: 8 additions & 3 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ android {
compileSdkVersion 28
defaultConfig {
applicationId "com.github.dhaval2404.imagepicker.support.sample"
minSdkVersion 21
minSdkVersion 19
targetSdkVersion 28
versionCode 2
versionName "1.1"
versionCode 4
versionName "1.3"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
Expand All @@ -25,6 +25,10 @@ android {
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {
Expand All @@ -35,6 +39,7 @@ dependencies {
implementation "com.android.support:support-v4:28.0.0"
implementation "com.android.support:design:28.0.0"
implementation "com.android.support:cardview-v7:28.0.0"
implementation 'com.github.florent37:inline-activity-result-kotlin:1.0.1'

//Image Loading Lib
implementation 'com.github.bumptech.glide:glide:4.9.0'
Expand Down
Loading

0 comments on commit c398730

Please sign in to comment.