Skip to content

Commit 688599c

Browse files
AppExternal Filewriter kotlin v3
1 parent 180f15e commit 688599c

6 files changed

Lines changed: 173 additions & 52 deletions

File tree

androidexternalfilewriter-kotlin/build.gradle

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ apply plugin: 'kotlin-android'
33
apply from: 'https://raw.githubusercontent.com/PrashamTrivedi/JCenter/master/installv1.gradle'
44
apply from: 'https://raw.githubusercontent.com/PrashamTrivedi/JCenter/master/bintrayv1.gradle'
55
android {
6-
compileSdkVersion 23
7-
buildToolsVersion "23.0.2"
6+
compileSdkVersion rootProject.ext.compileSdkVersion
7+
buildToolsVersion rootProject.ext.buildToolsVersion
88

99
defaultConfig {
1010
minSdkVersion 17
11-
targetSdkVersion 23
11+
targetSdkVersion 25
1212
versionCode 1
1313
versionName "1.0"
1414
}
@@ -26,12 +26,12 @@ android {
2626
dependencies {
2727
compile fileTree(dir: 'libs', include: ['*.jar'])
2828
testCompile 'junit:junit:4.12'
29-
compile 'com.android.support:appcompat-v7:23.2.1'
29+
compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibVersion"
3030
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
31-
compile 'com.creativeelites:kutils:0.4@aar'
31+
compile 'com.creativeelites:kutils:0.6@aar'
3232
}
3333
buildscript {
34-
ext.kotlin_version = '1.0.1-2'
34+
ext.kotlin_version = '1.1.2-4'
3535
repositories {
3636
mavenCentral()
3737
}

androidexternalfilewriter-kotlin/gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
POM_NAME=androidexternalfilewriter-kotlin
22
POM_ARTIFACT_ID=androidexternalfilewriter-kotlin
33
POM_PACKAGING=aar
4-
VERSION_NAME=0.2
5-
VERSION_CODE=2
4+
VERSION_NAME=0.3
5+
VERSION_CODE=3
66
GROUP=com.creativeelites
77
POM_DESCRIPTION=Android External FileWriter
88
POM_URL=https://github.com/PrashamTrivedi/AndroidExternalFileWriter

androidexternalfilewriter-kotlin/src/main/java/com/celites/androidexternalfilewriter_kotlin/KotlinStorageAccessFileWriter.kt

Lines changed: 144 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,61 @@
11
package com.celites.androidexternalfilewriter_kotlin
22

33
import android.app.Activity
4+
import android.content.Context
45
import android.content.Intent
56
import android.content.SharedPreferences
7+
import android.net.Uri
8+
import android.os.Build
69
import android.preference.PreferenceManager
10+
import android.support.annotation.RequiresApi
11+
import android.support.v4.app.Fragment
712
import android.support.v4.content.ContextCompat
813
import android.support.v4.provider.DocumentFile
914
import android.text.TextUtils
1015
import com.celites.kutils.isEmptyString
16+
import com.celites.kutils.remove
1117
import java.io.FileNotFoundException
1218
import java.io.FileOutputStream
1319
import java.io.IOException
1420

1521
/**
1622
* Created by Prasham on 4/11/2016.
1723
*/
18-
public class KotlinStorageAccessFileWriter(activity: Activity, requestCode: Int) {
1924

20-
private val PARENT_URI_KEY = "APP_EXTERNAL_PARENT_FILE_URI"
21-
lateinit var activity: Activity
25+
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
26+
public class KotlinStorageAccessFileWriter(requestCode: Int) {
27+
28+
29+
public val PARENT_URI_KEY = "APP_EXTERNAL_PARENT_FILE_URI"
30+
var activity: Activity? = null
31+
set(value) {
32+
value?.let {
33+
field = value
34+
context = value
35+
initProcessWithActivity(requestCode, value)
36+
}
37+
38+
}
39+
var fragment: Fragment? = null
40+
set(value) {
41+
value?.let {
42+
field = value
43+
context = value.context as Context
44+
initProcessWithFragment(requestCode, value)
45+
}
46+
47+
}
48+
49+
50+
public fun startWithContext(context: Context) {
51+
this.context = context
52+
val isExternaDirAvailable = isExternalDirAvailable()
53+
if (isExternaDirAvailable) {
54+
createAppDirectory()
55+
}
56+
}
57+
58+
lateinit var context: Context
2259
lateinit var appCacheDirectory: DocumentFile
2360
lateinit var appDirectory: DocumentFile
2461
lateinit var externalCacheDirectory: DocumentFile
@@ -28,17 +65,57 @@ public class KotlinStorageAccessFileWriter(activity: Activity, requestCode: Int)
2865
private val canNotCreateDirectory = "Can not create directory: "
2966
private val canNotWriteFile = "Can not write file: "
3067

31-
/**
32-
* Inits new SAFFileWriter object, it will first check whether we already have a parent directory with proper uri access or not.
3368

34-
* @param activity:
35-
* * Activity for context and starting request for OPEN_DOCUMENT_TREE
36-
* *
37-
* @param requestCode:
38-
* * Request code to listen to OPEN_DOCUMENT_TREE
39-
*/
40-
init {
41-
val dirs = ContextCompat.getExternalCacheDirs(activity)
69+
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
70+
private fun initProcessWithActivity(requestCode: Int, activity: Activity) {
71+
initCacheDirs()
72+
preferences = PreferenceManager.getDefaultSharedPreferences(context)
73+
val isExternaDirAvailable = isExternalDirAvailable()
74+
if (!isExternaDirAvailable) {
75+
76+
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
77+
activity.startActivityForResult(intent, requestCode)
78+
}
79+
}
80+
81+
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
82+
private fun initProcessWithFragment(requestCode: Int, fragment: Fragment) {
83+
initCacheDirs()
84+
preferences = PreferenceManager.getDefaultSharedPreferences(context)
85+
val isExternaDirAvailable = isExternalDirAvailable()
86+
if (!isExternaDirAvailable) {
87+
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
88+
fragment.startActivityForResult(intent, requestCode)
89+
}
90+
}
91+
92+
public fun checkIfExternalDirAvailable(context: Context): Boolean {
93+
initCacheDirs()
94+
preferences = PreferenceManager.getDefaultSharedPreferences(context)
95+
val isExternaDirAvailable = isExternalDirAvailable()
96+
return isExternaDirAvailable
97+
}
98+
99+
fun isExternalDirAvailable(): Boolean {
100+
initCacheDirs()
101+
preferences = PreferenceManager.getDefaultSharedPreferences(context)
102+
val externalDirUrl = preferences.getString(PARENT_URI_KEY, "")
103+
val isExternalDirEmpty = externalDirUrl.isEmptyString()
104+
if (!isExternalDirEmpty) {
105+
externalParentFile = DocumentFile.fromTreeUri(context, Uri.parse(externalDirUrl))
106+
try {
107+
createAppDirectory()
108+
} catch(e: Exception) {
109+
preferences.remove(PARENT_URI_KEY)
110+
return false
111+
}
112+
}
113+
return !isExternalDirEmpty
114+
}
115+
116+
117+
private fun initCacheDirs() {
118+
val dirs = ContextCompat.getExternalCacheDirs(context)
42119
if (dirs.size > 1) {
43120
val dir = dirs[1]
44121
if (dir != null) {
@@ -49,12 +126,6 @@ public class KotlinStorageAccessFileWriter(activity: Activity, requestCode: Int)
49126
} else {
50127
externalCacheDirectory = DocumentFile.fromFile(dirs[0])
51128
}
52-
preferences = PreferenceManager.getDefaultSharedPreferences(activity)
53-
val externalDirUrl = preferences.getString(PARENT_URI_KEY, "")
54-
if (externalDirUrl.isEmptyString()) {
55-
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
56-
activity.startActivityForResult(intent, requestCode)
57-
}
58129
}
59130

60131

@@ -102,11 +173,28 @@ public class KotlinStorageAccessFileWriter(activity: Activity, requestCode: Int)
102173
return file != null && file.isDirectory
103174
}
104175

176+
@RequiresApi(Build.VERSION_CODES.KITKAT)
177+
fun hasPermissions(file: DocumentFile): Boolean {
178+
val persistedUriPermissions = context.getContentResolver().persistedUriPermissions
179+
val filterForPermission = persistedUriPermissions.filter { it.uri == file.uri && it.isReadPermission && it.isWritePermission }
180+
val hasPermissions = filterForPermission.isNotEmpty()
181+
return hasPermissions
182+
}
183+
105184
/** Creates app directory */
106185
private fun createAppDirectory() {
107-
val directoryName = activity.getString(activity.applicationInfo.labelRes)
108-
appDirectory = externalParentFile?.createDirectory(directoryName)
109-
appCacheDirectory = externalCacheDirectory?.createDirectory(directoryName)
186+
val directoryName = context.getString(context.applicationInfo.labelRes)
187+
if (isDirectoryExists(directoryName, externalParentFile)) {
188+
appDirectory = externalParentFile.findFile(directoryName)
189+
} else {
190+
appDirectory = externalParentFile.createDirectory(directoryName)
191+
}
192+
if (isDirectoryExists(directoryName, externalCacheDirectory)) {
193+
appCacheDirectory = externalCacheDirectory.findFile(directoryName)
194+
} else {
195+
appCacheDirectory = externalCacheDirectory.createDirectory(directoryName)
196+
}
197+
110198
}
111199

112200
/**
@@ -122,18 +210,19 @@ public class KotlinStorageAccessFileWriter(activity: Activity, requestCode: Int)
122210
* @throws ExternalFileWriterException
123211
* * if external storage is not available
124212
*/
125-
fun createSubdirectory(directoryName: String, inCache: Boolean): DocumentFile? {
213+
fun createSubdirectory(directoryName: String, inCache: Boolean = false): DocumentFile? {
126214
getAppDirectory()
127215
val appDirectory = getAppDirectory(inCache)
128216
if (!isDirectoryExists(directoryName, inCache)) {
129217

130-
return appDirectory?.createDirectory(directoryName)
218+
return appDirectory.createDirectory(directoryName)
131219
} else {
132-
return appDirectory?.findFile(directoryName)
220+
return appDirectory.findFile(directoryName)
133221
}
134222
}
135223

136224
fun getAppDirectory(inCache: Boolean = false): DocumentFile {
225+
137226
return if (inCache) appCacheDirectory else appDirectory
138227
}
139228

@@ -153,16 +242,24 @@ public class KotlinStorageAccessFileWriter(activity: Activity, requestCode: Int)
153242

154243
private fun getDocumentFile(displayName: String, inCache: Boolean): DocumentFile? {
155244
val appDirectory = getAppDirectory(inCache)
156-
return appDirectory?.findFile(displayName)
245+
return appDirectory.findFile(displayName)
157246
}
158247

159-
fun handleResult(requestCode: Int, resultCode: Int, data: Intent) {
248+
fun handleResult(requestCode: Int, resultCode: Int, data: Intent?, handlingFinished: () -> Unit = {}, askForPersistableUriPermission: Boolean = true) {
160249
if (resultCode == Activity.RESULT_OK) {
161250
if (requestCode == this.requestCode) {
162-
val treeUri = data.data
163-
externalParentFile = DocumentFile.fromTreeUri(activity, treeUri)
164-
preferences.edit().putString(PARENT_URI_KEY, externalParentFile?.getUri().toString())
165-
getAppDirectory()
251+
data?.let {
252+
val treeUri = it.data
253+
if (askForPersistableUriPermission) {
254+
val takeFlags = it.flags and (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
255+
context.contentResolver.takePersistableUriPermission(treeUri, takeFlags)
256+
}
257+
externalParentFile = DocumentFile.fromTreeUri(context, treeUri)
258+
preferences.edit().putString(PARENT_URI_KEY, externalParentFile.getUri().toString()).apply()
259+
createAppDirectory()
260+
handlingFinished()
261+
}
262+
166263

167264
}
168265
}
@@ -231,8 +328,8 @@ public class KotlinStorageAccessFileWriter(activity: Activity, requestCode: Int)
231328
*/
232329
@Throws(FileNotFoundException::class)
233330
private fun writeDataToFile(file: DocumentFile, data: ByteArray) {
234-
val fileDescriptor = activity.contentResolver.openFileDescriptor(file.uri, "w")
235-
var out: FileOutputStream? = null
331+
val fileDescriptor = context.contentResolver.openFileDescriptor(file.uri, "w")
332+
val out: FileOutputStream?
236333
if (fileDescriptor != null) {
237334
out = FileOutputStream(fileDescriptor.fileDescriptor)
238335
try {
@@ -336,4 +433,18 @@ public class KotlinStorageAccessFileWriter(activity: Activity, requestCode: Int)
336433
return createFile(fileName, getAppDirectory(inCache), mimeType)
337434
}
338435

436+
public fun moveFile(file: DocumentFile, destinationDir: DocumentFile): Boolean {
437+
copyFile(destinationDir, file)
438+
return file.delete()
439+
}
440+
441+
public fun KotlinStorageAccessFileWriter.copyFile(destinationDir: DocumentFile, file: DocumentFile) {
442+
val bytesFromFile = getBytesFromFile(file)
443+
writeDataToFile(destinationDir, file.name, bytesFromFile, file.type)
444+
}
445+
446+
public fun getBytesFromFile(file: DocumentFile): ByteArray {
447+
val inputStream = context.contentResolver.openInputStream(file.uri)
448+
return inputStream.readBytes()
449+
}
339450
}

androidexternalfilewriter/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ apply plugin: 'com.android.library'
22
apply from: 'https://raw.githubusercontent.com/PrashamTrivedi/JCenter/master/installv1.gradle'
33
apply from: 'https://raw.githubusercontent.com/PrashamTrivedi/JCenter/master/bintrayv1.gradle'
44
android {
5-
compileSdkVersion 23
6-
buildToolsVersion "23.0.2"
5+
compileSdkVersion rootProject.ext.compileSdkVersion
6+
buildToolsVersion rootProject.ext.buildToolsVersion
77

88
defaultConfig {
99
minSdkVersion 10
10-
targetSdkVersion 23
10+
targetSdkVersion 25
1111
versionCode 1
1212
versionName "1.0"
1313
}
@@ -20,7 +20,7 @@ android {
2020
}
2121

2222
dependencies {
23-
compile 'com.android.support:appcompat-v7:23.1.1'
23+
compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibVersion"
2424
compile fileTree(dir: 'libs', include: ['*.jar'])
2525
compile 'com.celites:devutils:1.0@aar'
2626
}

app/build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
apply plugin: 'com.android.application'
22

33
android {
4-
compileSdkVersion 23
5-
buildToolsVersion "23.0.2"
4+
compileSdkVersion rootProject.ext.compileSdkVersion
5+
buildToolsVersion rootProject.ext.buildToolsVersion
66

77
defaultConfig {
88
applicationId "com.celites.appexternalfilewriter"
99
minSdkVersion 17
10-
targetSdkVersion 23
10+
targetSdkVersion 25
1111
versionCode 1
1212
versionName "1.0"
1313
}
@@ -21,8 +21,8 @@ android {
2121

2222
dependencies {
2323
compile fileTree(dir: 'libs', include: ['*.jar'])
24-
compile 'com.creativeelites:androidexternalfilewriter-kotlin:0.1'
25-
compile 'com.android.support:appcompat-v7:23.1.1'
24+
compile 'com.creativeelites:androidexternalfilewriter-kotlin:0.2'
25+
compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibVersion"
2626
// compile (':androidexternalfilewriter')
2727
compile project(':androidexternalfilewriter')
2828
}

build.gradle

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,26 @@
33
buildscript {
44
repositories {
55
jcenter()
6+
maven {
7+
url 'https://maven.google.com'
8+
}
69
}
710
dependencies {
8-
classpath 'com.android.tools.build:gradle:2.1.0-alpha5'
11+
classpath 'com.android.tools.build:gradle:3.0.0-alpha3'
912
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
10-
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
13+
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
1114
// NOTE: Do not place your application dependencies here; they belong
1215
// in the individual module build.gradle files
1316
}
1417
}
1518

19+
20+
ext {
21+
buildToolsVersion = "25.0.3"
22+
compileSdkVersion = 25
23+
supportLibVersion = "25.3.1"
24+
}
25+
1626
allprojects {
1727
repositories {
1828
maven {

0 commit comments

Comments
 (0)