Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions imagepicker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ plugins {
apply from: "../ktlint.gradle"

android {
compileSdkVersion 30
compileSdkVersion 33

defaultConfig {
minSdkVersion 19
targetSdkVersion 30
targetSdkVersion 33
versionCode 16
versionName "2.1"

Expand Down
16 changes: 11 additions & 5 deletions imagepicker/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.dhaval2404.imagepicker">

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- For Android 10+ consider using attribute android:requestLegacyExternalStorage -->
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application>

<activity
android:name=".ImagePickerActivity"
android:screenOrientation="unspecified"
Expand All @@ -18,13 +27,10 @@
android:authorities="${applicationId}.imagepicker.provider"
android:exported="false"
android:grantUriPermissions="true">

<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/image_picker_provider_paths" />

</provider>

</application>

<queries>
Expand All @@ -38,4 +44,4 @@
</intent>
</queries>

</manifest>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ open class ImagePicker {
}
},
dismissListener
)
,activity)

} else {
onResult(createIntent())
}
Expand All @@ -328,7 +329,7 @@ open class ImagePicker {
}
},
dismissListener
)
,activity )
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
package com.github.dhaval2404.imagepicker

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.github.dhaval2404.imagepicker.constant.ImageProvider
import com.github.dhaval2404.imagepicker.provider.CameraProvider
import com.github.dhaval2404.imagepicker.provider.CompressionProvider
Expand All @@ -21,17 +15,25 @@ import com.github.dhaval2404.imagepicker.util.FileUriUtils
* @version 1.0
* @since 04 January 2019
*/
import android.Manifest
import android.content.Intent
import android.content.Context
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
/*import com.example.imagepicker.ImagePicker
import com.example.imagepicker.utils.FileUriUtils*/

class ImagePickerActivity : AppCompatActivity() {

companion object {
private const val TAG = "image_picker"

internal fun getCancelledIntent(context: Context): Intent {
val intent = Intent()
val message = context.getString(R.string.error_task_cancelled)
intent.putExtra(ImagePicker.EXTRA_ERROR, message)
return intent
}
private const val REQUEST_CODE_STORAGE_PERMISSION = 100
}

private var mGalleryProvider: GalleryProvider? = null
Expand All @@ -44,85 +46,125 @@ class ImagePickerActivity : AppCompatActivity() {
loadBundle(savedInstanceState)
}

/**
* Save all appropriate activity state.
*/
public override fun onSaveInstanceState(outState: Bundle) {
mCameraProvider?.onSaveInstanceState(outState)
mCropProvider.onSaveInstanceState(outState)
super.onSaveInstanceState(outState)
}

/**
* Parse Intent Bundle and initialize variables
*/
private fun loadBundle(savedInstanceState: Bundle?) {
/* private fun loadBundle(savedInstanceState: Bundle?) {
// Create Crop Provider
mCropProvider = CropProvider(this)
mCropProvider.onRestoreInstanceState(savedInstanceState)

// Create Compression Provider
mCompressionProvider = CompressionProvider(this)

// Retrieve Image Provider
// Check and request permissions based on Android version
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Marshmallow and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // Android 13 (API level 33) and above
// Request permission only for accessing photos
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_MEDIA_IMAGES), REQUEST_CODE_STORAGE_PERMISSION)
} else {
initImageProvider(savedInstanceState)
}
} else {
// Request permission for accessing photos and videos
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_CODE_STORAGE_PERMISSION)
} else {
initImageProvider(savedInstanceState)
}
}
} else {
// For devices below Marshmallow, permissions are granted at installation
initImageProvider(savedInstanceState)
}
}*/

private fun loadBundle(savedInstanceState: Bundle?) {

mCropProvider = CropProvider(this)
mCropProvider.onRestoreInstanceState(savedInstanceState)
mCompressionProvider = CompressionProvider(this)


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT >=33) {
// Android 13 and above photos only
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.READ_MEDIA_IMAGES),
REQUEST_CODE_STORAGE_PERMISSION
)
} else {
initImageProvider(savedInstanceState)
}
} else {
// Android 12 and below
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
REQUEST_CODE_STORAGE_PERMISSION
)
} else {
initImageProvider(savedInstanceState)
}
}
} else {
initImageProvider(savedInstanceState)
}
}





private fun initImageProvider(savedInstanceState: Bundle?) {
val provider: ImageProvider? =
intent?.getSerializableExtra(ImagePicker.EXTRA_IMAGE_PROVIDER) as ImageProvider?

// Create Gallery/Camera Provider
when (provider) {
ImageProvider.GALLERY -> {
mGalleryProvider = GalleryProvider(this)
// Pick Gallery Image
savedInstanceState ?: mGalleryProvider?.startIntent()
}
ImageProvider.CAMERA -> {
mCameraProvider = CameraProvider(this)
mCameraProvider?.onRestoreInstanceState(savedInstanceState)
// Pick Camera Image
savedInstanceState ?: mCameraProvider?.startIntent()
}
else -> {
// Something went Wrong! This case should never happen
Log.e(TAG, "Image provider can not be null")
Log.e(TAG, "Image provider cannot be null")
setError(getString(R.string.error_task_cancelled))
}
}
}

/**
* Dispatch incoming result to the correct provider.
*/
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
mCameraProvider?.onRequestPermissionsResult(requestCode)
if (requestCode == REQUEST_CODE_STORAGE_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initImageProvider(null)
} else {
setError("Permission denied")
}
}
}

override fun onSaveInstanceState(outState: Bundle) {
mCameraProvider?.onSaveInstanceState(outState)
mCropProvider.onSaveInstanceState(outState)
super.onSaveInstanceState(outState)
}

/**
* Dispatch incoming result to the correct provider.
*/
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
mCameraProvider?.onActivityResult(requestCode, resultCode, data)
mGalleryProvider?.onActivityResult(requestCode, resultCode, data)
mCropProvider.onActivityResult(requestCode, resultCode, data)
}

/**
* Handle Activity Back Press
*/
override fun onBackPressed() {
setResultCancel()
}

/**
* {@link CameraProvider} and {@link GalleryProvider} Result will be available here.
*
* @param uri Capture/Gallery image Uri
*/
fun setImage(uri: Uri) {
when {
mCropProvider.isCropEnabled() -> mCropProvider.startIntent(uri)
Expand All @@ -131,16 +173,7 @@ class ImagePickerActivity : AppCompatActivity() {
}
}

/**
* {@link CropProviders} Result will be available here.
*
* Check if compression is enable/required. If yes then start compression else return result.
*
* @param uri Crop image uri
*/
fun setCropImage(uri: Uri) {
// Delete Camera file after crop. Else there will be two image for the same action.
// In case of Gallery Provider, we will get original image path, so we will not delete that.
mCameraProvider?.delete()

if (mCompressionProvider.isCompressionRequired(uri)) {
Expand All @@ -150,29 +183,12 @@ class ImagePickerActivity : AppCompatActivity() {
}
}

/**
* {@link CompressionProvider} Result will be available here.
*
* @param uri Compressed image Uri
*/
fun setCompressedImage(uri: Uri) {
// This is the case when Crop is not enabled

// Delete Camera file after crop. Else there will be two image for the same action.
// In case of Gallery Provider, we will get original image path, so we will not delete that.
mCameraProvider?.delete()

// If crop file is not null, Delete it after crop
mCropProvider.delete()

setResult(uri)
}

/**
* Set Result, Image is successfully capture/picked/cropped/compressed.
*
* @param uri final image Uri
*/
private fun setResult(uri: Uri) {
val intent = Intent()
intent.data = uri
Expand All @@ -181,23 +197,22 @@ class ImagePickerActivity : AppCompatActivity() {
finish()
}

/**
* User has cancelled the task
*/
fun setResultCancel() {
setResult(Activity.RESULT_CANCELED, getCancelledIntent(this))
finish()
}

/**
* Error occurred while processing image
*
* @param message Error Message
*/
fun setError(message: String) {
val intent = Intent()
intent.putExtra(ImagePicker.EXTRA_ERROR, message)
setResult(ImagePicker.RESULT_ERROR, intent)
finish()
}
}

internal fun getCancelledIntent(context: Context): Intent {
val intent = Intent()
val message = context.getString(R.string.error_task_cancelled)
intent.putExtra(ImagePicker.EXTRA_ERROR, message)
return intent
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import java.io.File
* @version 1.0
* @since 04 January 2019
*/
abstract class BaseProvider(protected val activity: ImagePickerActivity) :
abstract class BaseProvider(protected open val activity: ImagePickerActivity) :
ContextWrapper(activity) {

fun getFileDir(path: String?): File {
Expand Down
Loading