├── sample
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ ├── values-v21
│ │ │ │ └── styles.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── mlsdev
│ │ │ └── sample
│ │ │ └── MainActivity.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── mlsdev
│ │ │ └── sample
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── mlsdev
│ │ └── sample
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── library
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── mlsdev
│ │ │ │ └── rximagepicker
│ │ │ │ ├── Sources.kt
│ │ │ │ ├── RxImageConverters.kt
│ │ │ │ └── RxImagePicker.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── mlsdev
│ │ │ └── library
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── mlsdev
│ │ └── rximagepicker
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── CHANGELOG.md
├── gradle.properties
├── LICENSE
├── gradlew.bat
├── README.md
└── gradlew
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':library'
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/
4 | .DS_Store
5 | /build
6 | /captures
7 | **/*.iml
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RxImagePicker/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | library
3 |
4 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RxImagePicker/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RxImagePicker/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RxImagePicker/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RxImagePicker/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RxImagePicker/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/java/com/mlsdev/rximagepicker/Sources.kt:
--------------------------------------------------------------------------------
1 | package com.mlsdev.rximagepicker
2 |
3 | enum class Sources {
4 | CAMERA, GALLERY, DOCUMENTS, CHOOSER
5 | }
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #303F9F
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Sep 24 18:42:35 EEST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 8dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 | >
2 |
7 |
8 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### Version 2.2.0
2 | Migrate project to Kotlin
3 | Add support for Documents and Chooser intent
4 |
5 | ### Version 2.0.3
6 | Migrate request from Activity to Fragment
7 |
8 | ### Version 2.0.0
9 |
10 | Migrate to RxJava2
11 |
12 | ### Version 1.3.1
13 |
14 | Pick multiple images for Api level 18+
15 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/test/java/com/mlsdev/sample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.sample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Sample
3 | Settings
4 | Load from Uri
5 | Convert Uri to file
6 | Convert Uri to Bitmap
7 | Pick image
8 |
9 |
--------------------------------------------------------------------------------
/library/src/test/java/com/mlsdev/library/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.rximagepicker;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/sample/src/androidTest/java/com/mlsdev/sample/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.sample;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/mlsdev/rximagepicker/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.rximagepicker;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/Frederikos/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/Frederikos/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 | android.enableJetifier=true
20 | android.useAndroidX=true
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Sergey Glebov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'kotlin-kapt'
5 |
6 | android {
7 | compileSdkVersion 28
8 |
9 | defaultConfig {
10 | applicationId "com.mlsdev.sample"
11 | minSdkVersion 16
12 | targetSdkVersion 28
13 | versionCode 1
14 | versionName "1.0"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | implementation project(':library')
26 | implementation 'androidx.appcompat:appcompat:1.0.2'
27 | implementation 'com.google.android.material:material:1.0.0'
28 | implementation 'com.github.bumptech.glide:glide:4.8.0'
29 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
30 | implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
31 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
32 | testImplementation 'junit:junit:4.12'
33 | }
34 |
35 | repositories {
36 | mavenCentral()
37 | }
38 |
--------------------------------------------------------------------------------
/library/src/main/java/com/mlsdev/rximagepicker/RxImageConverters.kt:
--------------------------------------------------------------------------------
1 | package com.mlsdev.rximagepicker
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.net.Uri
6 | import android.provider.MediaStore
7 | import android.util.Log
8 | import io.reactivex.Observable
9 | import io.reactivex.ObservableOnSubscribe
10 | import io.reactivex.android.schedulers.AndroidSchedulers
11 | import io.reactivex.schedulers.Schedulers
12 | import java.io.File
13 | import java.io.FileOutputStream
14 | import java.io.IOException
15 | import java.io.InputStream
16 |
17 | object RxImageConverters {
18 |
19 | fun uriToFile(context: Context, uri: Uri, file: File): Observable {
20 | return Observable.create(ObservableOnSubscribe { emitter ->
21 | try {
22 | val inputStream = context.contentResolver.openInputStream(uri)
23 | file.copyInputStreamToFile(inputStream!!)
24 | emitter.onNext(file)
25 | emitter.onComplete()
26 | } catch (e: Exception) {
27 | Log.e(RxImageConverters::class.java.simpleName, "Error converting uri", e)
28 | emitter.onError(e)
29 | }
30 | }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())
31 | }
32 |
33 | fun uriToBitmap(context: Context, uri: Uri): Observable {
34 | return Observable.create(ObservableOnSubscribe { emitter ->
35 | try {
36 | val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, uri)
37 | emitter.onNext(bitmap)
38 | emitter.onComplete()
39 | } catch (e: IOException) {
40 | Log.e(RxImageConverters::class.java.simpleName, "Error converting uri", e)
41 | emitter.onError(e)
42 | }
43 | }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())
44 | }
45 |
46 | private fun File.copyInputStreamToFile(inputStream: InputStream) {
47 | inputStream.use { input ->
48 | this.outputStream().use { fileOut ->
49 | input.copyTo(fileOut)
50 | }
51 | }
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/mlsdev/sample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mlsdev.sample
2 |
3 | import android.graphics.Bitmap
4 | import android.os.Bundle
5 | import android.os.Environment
6 | import android.widget.ImageView
7 | import android.widget.RadioGroup
8 | import android.widget.Toast
9 | import androidx.appcompat.app.AppCompatActivity
10 | import com.bumptech.glide.Glide
11 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
12 | import com.google.android.material.floatingactionbutton.FloatingActionButton
13 | import com.mlsdev.rximagepicker.RxImageConverters
14 | import com.mlsdev.rximagepicker.RxImagePicker
15 | import com.mlsdev.rximagepicker.Sources
16 | import io.reactivex.Observable
17 | import java.io.File
18 |
19 | class MainActivity : AppCompatActivity() {
20 |
21 | private lateinit var ivPickedImage: ImageView
22 | private lateinit var converterRadioGroup: RadioGroup
23 |
24 | override fun onCreate(savedInstanceState: Bundle?) {
25 | super.onCreate(savedInstanceState)
26 | setContentView(R.layout.activity_main)
27 |
28 | ivPickedImage = findViewById(R.id.iv_picked_image)
29 | val fabCamera = findViewById(R.id.fab_pick_camera)
30 | val fabGallery = findViewById(R.id.fab_pick_gallery)
31 | val fabDocuments = findViewById(R.id.fab_pick_documents)
32 | val fabChooser = findViewById(R.id.fab_pick_chooser)
33 | converterRadioGroup = findViewById(R.id.radio_group)
34 | converterRadioGroup.check(R.id.radio_uri)
35 |
36 | fabCamera.setOnClickListener { pickImageFromSource(Sources.CAMERA) }
37 | fabGallery.setOnClickListener { pickImageFromSource(Sources.GALLERY) }
38 | fabDocuments.setOnClickListener { pickImageFromSource(Sources.DOCUMENTS) }
39 | fabChooser.setOnClickListener { pickImageFromSource(Sources.CHOOSER) }
40 | }
41 |
42 | private fun pickImageFromSource(source: Sources) {
43 | RxImagePicker.with(supportFragmentManager).requestImage(source, getString(R.string.label_pick_image))
44 | .flatMap { uri ->
45 | when (converterRadioGroup.checkedRadioButtonId) {
46 | R.id.radio_file -> RxImageConverters.uriToFile(this@MainActivity, uri, createTempFile())
47 | R.id.radio_bitmap -> RxImageConverters.uriToBitmap(this@MainActivity, uri)
48 | else -> Observable.just(uri)
49 | }
50 | }
51 | .subscribe({
52 | onImagePicked(it)
53 | }, {
54 | Toast.makeText(this@MainActivity, java.lang.String.format("Error: %s", it), Toast.LENGTH_LONG).show()
55 | })
56 | }
57 |
58 | private fun onImagePicked(result: Any) {
59 | Toast.makeText(this, java.lang.String.format("Result: %s", result), Toast.LENGTH_LONG).show()
60 | if (result is Bitmap) {
61 | ivPickedImage.setImageBitmap(result)
62 | } else {
63 | Glide.with(this)
64 | .load(result) // works for File or Uri
65 | .transition(DrawableTransitionOptions().crossFade())
66 | .into(ivPickedImage)
67 | }
68 | }
69 |
70 | private fun createTempFile(): File {
71 | return File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().toString() + "_image.jpeg")
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RxImagePicker
2 |
3 | An easy way to get image from Gallery or Camera with request runtime permission on Android M using RxJava2
4 |
5 | ## Setup
6 |
7 | To use this library your ` minSdkVersion` must be >= 16.
8 |
9 | In your build.gradle :
10 |
11 | ```gradle
12 | dependencies {
13 | implementation 'com.mlsdev.rximagepicker:library:2.2.1'
14 | }
15 | ```
16 |
17 | ## Example
18 |
19 | ```kotlin
20 | RxImagePicker.with(supportFragmentManager).requestImage(Sources.CAMERA).subscribe {
21 | //Get image by uri using one of image loading libraries. I use Glide in sample app.
22 | }
23 | ```
24 |
25 | Request image from gallery :
26 |
27 | ```kotlin
28 | RxImagePicker.with(supportFragmentManager).requestImage(Sources.GALLERY).subscribe {
29 |
30 | }
31 | ```
32 |
33 | Request image from documents :
34 |
35 | ```kotlin
36 | RxImagePicker.with(supportFragmentManager).requestImage(Sources.DOCUMENTS).subscribe {
37 |
38 | }
39 | ```
40 |
41 | Use android chooser to get image :
42 |
43 | ```kotlin
44 | RxImagePicker.with(supportFragmentManager).requestImage(Sources.CHOOSER, "Chooser title").subscribe {
45 |
46 | }
47 | ```
48 |
49 | Request multiple images on Android Api level 18+ :
50 |
51 | ```kotlin
52 | RxImagePicker.with(supportFragmentManager).requestMultipleImages().subscribe {
53 | //Get images by uris.
54 | }
55 | ```
56 |
57 | ### Using converters
58 |
59 | ```java
60 | RxImagePicker.with(context).requestImage(Sources.GALLERY)
61 | .flatMap(new Function>() {
62 | @Override
63 | public ObservableSource apply(@NonNull Uri uri) throws Exception {
64 | return RxImageConverters.uriToBitmap(getContext(), uri);
65 | }
66 | }).subscribe(new Consumer() {
67 | @Override
68 | public void accept(@NonNull Bitmap bitmap) throws Exception {
69 | // Do something with Bitmap
70 | }
71 | });
72 | ```
73 |
74 | ```java
75 | RxImagePicker.with(context).requestImage(Sources.GALLERY)
76 | .flatMap(new Function>() {
77 | @Override
78 | public ObservableSource apply(@NonNull Uri uri) throws Exception {
79 | return RxImageConverters.uriToFile(getContext(), uri, new File("YOUR FILE"));
80 | }
81 | }).subscribe(new Consumer() {
82 | @Override
83 | public void accept(@NonNull File file) throws Exception {
84 | // Do something with your file copy
85 | }
86 | });
87 | ```
88 |
89 | ## Sample App
90 |
91 |
92 |
93 | ## Authors
94 | * [Sergey Glebov](mailto:glebov@mlsdev.com) ([frederikos][github-frederikos]), MLSDev
95 |
96 | ## License
97 | RxImagePicker is released under the MIT license. See LICENSE for details.
98 |
99 | ## About MLSDev
100 |
101 | [
][mlsdev]
102 |
103 | RxImagePicker is maintained by MLSDev, Inc. We specialize in providing all-in-one solution in mobile and web development. Our team follows Lean principles and works according to agile methodologies to deliver the best results reducing the budget for development and its timeline.
104 |
105 | Find out more [here][mlsdev] and don't hesitate to [contact us][contact]!
106 |
107 | [mlsdev]: http://mlsdev.com
108 | [contact]: http://mlsdev.com/contact_us
109 | [github-frederikos]: https://github.com/frederikos
110 |
111 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
18 |
19 |
20 |
21 |
25 |
26 |
31 |
32 |
38 |
39 |
46 |
47 |
54 |
55 |
62 |
63 |
64 |
65 |
72 |
73 |
78 |
79 |
84 |
85 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: "org.jetbrains.dokka-android"
3 | apply plugin: 'com.github.dcendents.android-maven'
4 | apply plugin: "com.jfrog.bintray"
5 | apply plugin: 'kotlin-android'
6 | apply plugin: 'kotlin-android-extensions'
7 | apply plugin: 'kotlin-kapt'
8 |
9 | def siteUrl = 'https://github.com/Frederikos/RxImagePicker'
10 | def gitUrl = 'https://github.com/Frederikos/RxImagePicker.git'
11 |
12 | version = "2.2.1"
13 | group = "com.mlsdev.rximagepicker"
14 |
15 | Properties properties = new Properties()
16 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
17 |
18 | bintray {
19 | user = properties.getProperty("bintray.user")
20 | key = properties.getProperty("bintray.apikey")
21 |
22 | configurations = ['archives']
23 | pkg {
24 | repo = "maven"
25 | name = "RxImagePicker"
26 | websiteUrl = siteUrl
27 | vcsUrl = gitUrl
28 | licenses = ["Apache-2.0"]
29 | publish = true
30 | }
31 | }
32 |
33 | android {
34 | compileSdkVersion 28
35 |
36 | defaultConfig {
37 | minSdkVersion 16
38 | targetSdkVersion 28
39 | versionCode 17
40 | versionName "2.2.1"
41 | }
42 |
43 | buildTypes {
44 | release {
45 | minifyEnabled false
46 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
47 | }
48 | }
49 | }
50 |
51 | dokka {
52 | outputFormat = 'html'
53 | outputDirectory = "$buildDir/javadoc"
54 | }
55 |
56 | install {
57 | repositories.mavenInstaller {
58 | pom {
59 | project {
60 | packaging 'aar'
61 | name 'RxImagePicker an easy way to get image from Gallery or Camera with request runtime permission on Android M. Using RxJava'
62 | url siteUrl
63 | licenses {
64 | license {
65 | name 'The Apache Software License, Version 2.0'
66 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
67 | }
68 | }
69 | developers {
70 | developer {
71 | id 'frederikos'
72 | name 'frederikos'
73 | email 'frederikoss@gmail.com'
74 | }
75 | }
76 | scm {
77 | connection gitUrl
78 | developerConnection gitUrl
79 | url siteUrl
80 |
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
87 | dependencies {
88 | compileOnly 'androidx.appcompat:appcompat:1.0.2'
89 | compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
90 | compileOnly 'io.reactivex.rxjava2:rxandroid:2.1.0'
91 | compileOnly 'io.reactivex.rxjava2:rxjava:2.2.2'
92 | testImplementation 'junit:junit:4.12'
93 | }
94 |
95 | if (project.hasProperty("kotlin")) { //Kotlin libraries
96 | task sourcesJar(type: Jar) {
97 | classifier = 'sources'
98 | from android.sourceSets.main.java.srcDirs
99 | }
100 |
101 | task javadoc(type: Javadoc, dependsOn: dokka) {
102 |
103 | }
104 | } else if (project.hasProperty("android")) {
105 | task sourcesJar(type: Jar) {
106 | classifier = 'sources'
107 | from android.sourceSets.main.java.srcDirs
108 | }
109 |
110 | task javadoc(type: Javadoc) {
111 | source = android.sourceSets.main.java.srcDirs
112 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
113 | }
114 | } else { // Java libraries
115 | task sourcesJar(type: Jar, dependsOn: classes) {
116 | classifier = 'sources'
117 | from sourceSets.main.allSource
118 | }
119 | }
120 |
121 | task javadocJar(type: Jar, dependsOn: javadoc) {
122 | classifier = 'javadoc'
123 | from javadoc.destinationDir
124 | // options.encoding = 'UTF-8'
125 | }
126 |
127 | artifacts {
128 | archives javadocJar
129 | archives sourcesJar
130 | }
131 |
132 | task findConventions << {
133 | println project.getConvention()
134 | }
135 | repositories {
136 | mavenCentral()
137 | }
138 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/library/src/main/java/com/mlsdev/rximagepicker/RxImagePicker.kt:
--------------------------------------------------------------------------------
1 | package com.mlsdev.rximagepicker
2 |
3 | import android.Manifest
4 | import android.annotation.TargetApi
5 | import android.app.Activity.RESULT_OK
6 | import android.content.ContentValues
7 | import android.content.Context
8 | import android.content.Intent
9 | import android.content.pm.PackageManager
10 | import android.net.Uri
11 | import android.os.Build
12 | import android.os.Bundle
13 | import android.provider.MediaStore
14 | import androidx.core.content.ContextCompat
15 | import androidx.fragment.app.Fragment
16 | import androidx.fragment.app.FragmentManager
17 | import io.reactivex.Observable
18 | import io.reactivex.subjects.PublishSubject
19 | import java.text.SimpleDateFormat
20 | import java.util.*
21 | import android.content.ComponentName
22 |
23 | class RxImagePicker : Fragment() {
24 |
25 | private lateinit var attachedSubject: PublishSubject
26 | private lateinit var publishSubject: PublishSubject
27 | private lateinit var publishSubjectMultipleImages: PublishSubject>
28 | private lateinit var canceledSubject: PublishSubject
29 |
30 | private var allowMultipleImages = false
31 | private var imageSource: Sources? = null
32 | private var chooserTitle: String? = null
33 |
34 | fun requestImage(source: Sources, chooserTitle: String?): Observable {
35 | this.chooserTitle = chooserTitle
36 | return requestImage(source)
37 | }
38 |
39 | fun requestImage(source: Sources): Observable {
40 | initSubjects()
41 | allowMultipleImages = false
42 | imageSource = source
43 | requestPickImage()
44 | return publishSubject.takeUntil(canceledSubject)
45 | }
46 |
47 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
48 | fun requestMultipleImages(): Observable> {
49 | initSubjects()
50 | imageSource = Sources.GALLERY
51 | allowMultipleImages = true
52 | requestPickImage()
53 | return publishSubjectMultipleImages.takeUntil(canceledSubject)
54 | }
55 |
56 | override fun onCreate(savedInstanceState: Bundle?) {
57 | super.onCreate(savedInstanceState)
58 | retainInstance = true
59 | }
60 |
61 | private fun initSubjects(){
62 | publishSubject = PublishSubject.create()
63 | attachedSubject = PublishSubject.create()
64 | canceledSubject = PublishSubject.create()
65 | publishSubjectMultipleImages = PublishSubject.create()
66 | }
67 |
68 | override fun onAttach(context: Context?) {
69 | super.onAttach(context)
70 | if (::attachedSubject.isInitialized.not() or
71 | ::publishSubject.isInitialized.not() or
72 | ::publishSubjectMultipleImages.isInitialized.not() or
73 | ::canceledSubject.isInitialized.not()){
74 | initSubjects()
75 | }
76 | attachedSubject.onNext(true)
77 | attachedSubject.onComplete()
78 | }
79 |
80 | override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
81 | if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
82 | pickImage()
83 | }
84 | }
85 |
86 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
87 | if (resultCode == RESULT_OK) {
88 | when (requestCode) {
89 | SELECT_PHOTO -> handleGalleryResult(data)
90 | TAKE_PHOTO -> onImagePicked(cameraPictureUrl)
91 | CHOOSER -> if (isPhoto(data)) {
92 | onImagePicked(cameraPictureUrl)
93 | } else {
94 | handleGalleryResult(data)
95 | }
96 | }
97 | } else {
98 | canceledSubject.onNext(requestCode)
99 | }
100 | }
101 |
102 | private fun isPhoto(data: Intent?): Boolean {
103 | return data == null || data.data == null && data.clipData == null
104 | }
105 |
106 | private fun handleGalleryResult(data: Intent?) {
107 | if (allowMultipleImages) {
108 | val imageUris = ArrayList()
109 | val clipData = data!!.clipData
110 | if (clipData != null) {
111 | for (i in 0 until clipData.itemCount) {
112 | imageUris.add(clipData.getItemAt(i).uri)
113 | }
114 | } else {
115 | imageUris.add(data.data)
116 | }
117 | onImagesPicked(imageUris)
118 | } else {
119 | onImagePicked(data!!.data)
120 | }
121 | }
122 |
123 | private fun requestPickImage() {
124 | if (!isAdded) {
125 | attachedSubject.subscribe { pickImage() }
126 | } else {
127 | pickImage()
128 | }
129 | }
130 |
131 | private fun pickImage() {
132 | if (!checkPermission()) {
133 | return
134 | }
135 |
136 | var chooseCode = 0
137 | var pictureChooseIntent: Intent? = null
138 |
139 | when (imageSource) {
140 | Sources.CAMERA -> {
141 | cameraPictureUrl = createImageUri()
142 | pictureChooseIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
143 | pictureChooseIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPictureUrl)
144 | grantWritePermission(context!!, pictureChooseIntent, cameraPictureUrl!!)
145 | chooseCode = TAKE_PHOTO
146 | }
147 | Sources.GALLERY -> {
148 | pictureChooseIntent = createPickFromGalleryIntent()
149 | chooseCode = SELECT_PHOTO
150 | }
151 | Sources.DOCUMENTS -> {
152 | pictureChooseIntent = createPickFromDocumentsIntent()
153 | chooseCode = SELECT_PHOTO
154 | }
155 | Sources.CHOOSER -> {
156 | pictureChooseIntent = createChooserIntent(chooserTitle)
157 | chooseCode = CHOOSER
158 | }
159 | }
160 |
161 | startActivityForResult(pictureChooseIntent, chooseCode)
162 | }
163 |
164 | private fun createChooserIntent(chooserTitle: String?): Intent {
165 | cameraPictureUrl = createImageUri()
166 | val cameraIntents = ArrayList()
167 | val captureIntent = Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE)
168 | val packageManager = context!!.packageManager
169 | val camList = packageManager.queryIntentActivities(captureIntent, 0)
170 | for (res in camList) {
171 | val packageName = res.activityInfo.packageName
172 | val intent = Intent(captureIntent)
173 | intent.component = ComponentName(res.activityInfo.packageName, res.activityInfo.name)
174 | intent.setPackage(packageName)
175 | intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPictureUrl)
176 | grantWritePermission(context!!, intent, cameraPictureUrl!!)
177 | cameraIntents.add(intent)
178 | }
179 | val galleryIntent = createPickFromDocumentsIntent()
180 | val chooserIntent = Intent.createChooser(galleryIntent, chooserTitle)
181 | chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toTypedArray())
182 |
183 | return chooserIntent
184 | }
185 |
186 | private fun createPickFromGalleryIntent(): Intent {
187 | var pictureChooseIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
188 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
189 | pictureChooseIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultipleImages)
190 | }
191 | return pictureChooseIntent
192 | }
193 |
194 | private fun createPickFromDocumentsIntent(): Intent {
195 | val pictureChooseIntent: Intent
196 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
197 | pictureChooseIntent = Intent(Intent.ACTION_OPEN_DOCUMENT)
198 | pictureChooseIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultipleImages)
199 | pictureChooseIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
200 | } else {
201 | pictureChooseIntent = Intent(Intent.ACTION_GET_CONTENT)
202 | }
203 | pictureChooseIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true)
204 | pictureChooseIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
205 | pictureChooseIntent.type = "image/*"
206 | return pictureChooseIntent
207 | }
208 |
209 | private fun checkPermission(): Boolean {
210 | return if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
211 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
212 | requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 0)
213 | }
214 | false
215 | } else {
216 | true
217 | }
218 | }
219 |
220 | private fun createImageUri(): Uri? {
221 | val contentResolver = activity!!.contentResolver
222 | val cv = ContentValues()
223 | val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
224 | cv.put(MediaStore.Images.Media.TITLE, timeStamp)
225 | return contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cv)
226 | }
227 |
228 | private fun grantWritePermission(context: Context, intent: Intent, uri: Uri) {
229 | val resInfoList = context.packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
230 | for (resolveInfo in resInfoList) {
231 | val packageName = resolveInfo.activityInfo.packageName
232 | context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
233 | }
234 | }
235 |
236 | private fun onImagesPicked(uris: List) {
237 | publishSubjectMultipleImages.onNext(uris)
238 | publishSubjectMultipleImages.onComplete()
239 | }
240 |
241 | private fun onImagePicked(uri: Uri?) {
242 | uri?.let {
243 | publishSubject.onNext(it)
244 | }
245 | publishSubject.onComplete()
246 | }
247 |
248 | companion object {
249 |
250 | private const val SELECT_PHOTO = 100
251 | private const val TAKE_PHOTO = 101
252 | private const val CHOOSER = 102
253 |
254 | private val TAG = RxImagePicker::class.java.simpleName
255 | private var cameraPictureUrl: Uri? = null
256 |
257 | fun with(fragmentManager: FragmentManager): RxImagePicker {
258 | var rxImagePickerFragment = fragmentManager.findFragmentByTag(TAG) as RxImagePicker?
259 | if (rxImagePickerFragment == null) {
260 | rxImagePickerFragment = RxImagePicker()
261 | fragmentManager.beginTransaction()
262 | .add(rxImagePickerFragment, TAG)
263 | .commit()
264 | }
265 | return rxImagePickerFragment
266 | }
267 | }
268 |
269 | }
270 |
--------------------------------------------------------------------------------