mirror of
https://github.com/geode-sdk/android-launcher.git
synced 2026-10-21 16:32:39 +00:00
fix file utils, move them to a separate class
This commit is contained in:
1 parent
498bbf4528
commit
dcfab5e001
6 files changed
+405
-232
No files matched your search
@@ -4,13 +4,22 @@
|
|||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<package android:name="com.robtopx.geometryjump" />
|
<package android:name="com.robtopx.geometryjump" />
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.OPEN_DOCUMENT" />
|
||||||
|
<category android:name="android.intent.category.OPENABLE" />
|
||||||
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
android:maxSdkVersion="32" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="32" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.wifi"
|
android:name="android.hardware.wifi"
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.geode.launcher.activityresult
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
|
|
||||||
|
open class GeodeOpenFileActivityResult : ActivityResultContract<GeodeOpenFileActivityResult.OpenFileParams, Uri?>() {
|
||||||
|
class OpenFileParams(val extraMimes: Array<String>, val defaultPath: Uri?) {}
|
||||||
|
override fun createIntent(context: Context, input: OpenFileParams): Intent {
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||||
|
.putExtra(Intent.EXTRA_MIME_TYPES, input.extraMimes)
|
||||||
|
.setType("*/*")
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
if (input.defaultPath != null) {
|
||||||
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, input.defaultPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun getSynchronousResult(
|
||||||
|
context: Context,
|
||||||
|
input: OpenFileParams
|
||||||
|
): SynchronousResult<Uri?>? = null
|
||||||
|
|
||||||
|
final override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
|
||||||
|
return intent.takeIf { resultCode == Activity.RESULT_OK }?.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.geode.launcher.activityresult
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
|
|
||||||
|
open class GeodeOpenFilesActivityResult : ActivityResultContract<GeodeOpenFilesActivityResult.OpenFileParams, List<@JvmSuppressWildcards Uri>>() {
|
||||||
|
class OpenFileParams(val extraMimes: Array<String>, val defaultPath: Uri?) {}
|
||||||
|
override fun createIntent(context: Context, input: OpenFileParams): Intent {
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||||
|
.putExtra(Intent.EXTRA_MIME_TYPES, input.extraMimes)
|
||||||
|
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||||
|
.setType("*/*")
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
if (input.defaultPath != null) {
|
||||||
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, input.defaultPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun getSynchronousResult(
|
||||||
|
context: Context,
|
||||||
|
input: OpenFileParams
|
||||||
|
): SynchronousResult<List<@JvmSuppressWildcards Uri>>? = null
|
||||||
|
|
||||||
|
final override fun parseResult(resultCode: Int, intent: Intent?): List<Uri> {
|
||||||
|
// Gracefully stolen from ActivityResultContracts.Intent.getclipDataUris
|
||||||
|
val clipData = intent.takeIf {
|
||||||
|
resultCode == Activity.RESULT_OK
|
||||||
|
}?.clipData
|
||||||
|
val resultSet = LinkedHashSet<Uri>()
|
||||||
|
intent?.data?.let { data ->
|
||||||
|
resultSet.add(data)
|
||||||
|
}
|
||||||
|
if (clipData == null && resultSet.isEmpty()) {
|
||||||
|
return emptyList()
|
||||||
|
} else if (clipData != null) {
|
||||||
|
for (i in 0 until clipData.itemCount) {
|
||||||
|
val uri = clipData.getItemAt(i).uri
|
||||||
|
if (uri != null) {
|
||||||
|
resultSet.add(uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ArrayList(resultSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.geode.launcher.activityresult
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
|
|
||||||
|
open class GeodeSaveFileActivityResult : ActivityResultContract<GeodeSaveFileActivityResult.SaveFileParams, Uri?>() {
|
||||||
|
class SaveFileParams(val mimeType: String?, val defaultPath: Uri?) {}
|
||||||
|
override fun createIntent(context: Context, input: SaveFileParams): Intent {
|
||||||
|
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
||||||
|
.setType(input.mimeType ?: "*/*")
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
if (input.defaultPath != null) {
|
||||||
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, input.defaultPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun getSynchronousResult(
|
||||||
|
context: Context,
|
||||||
|
input: SaveFileParams
|
||||||
|
): SynchronousResult<Uri?>? = null
|
||||||
|
|
||||||
|
final override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
|
||||||
|
return intent.takeIf { resultCode == Activity.RESULT_OK }?.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
package com.geode.launcher.utils
|
||||||
|
|
||||||
|
import android.content.ContentUris
|
||||||
|
import android.content.Context
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Environment
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class FileUtils {
|
||||||
|
// copied from https://stackoverflow.com/questions/17546101/get-real-path-for-uri-android
|
||||||
|
// i am actually very lazy to move this to a separate class
|
||||||
|
// hello zmx i moved it
|
||||||
|
companion object {
|
||||||
|
fun getRealPathFromURI(context: Context, uri: Uri): String? {
|
||||||
|
when {
|
||||||
|
// DocumentProvider
|
||||||
|
DocumentsContract.isDocumentUri(context, uri) -> {
|
||||||
|
when {
|
||||||
|
// ExternalStorageProvider
|
||||||
|
isExternalStorageDocument(uri) -> {
|
||||||
|
return handleExternalStorageDocument(context, uri)
|
||||||
|
}
|
||||||
|
isDownloadsDocument(uri) -> {
|
||||||
|
return handleDownloadsDocument(context, uri)
|
||||||
|
}
|
||||||
|
isMediaDocument(uri) -> {
|
||||||
|
return handleMediaDocument(context, uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add the geode provider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"content".equals(uri.scheme, ignoreCase = true) -> {
|
||||||
|
// Return the remote address
|
||||||
|
if (isGooglePhotosUri(uri)) return uri.lastPathSegment
|
||||||
|
// This happened with a directory
|
||||||
|
if (isExternalStorageDocument(uri)) {
|
||||||
|
return handleExternalStorageDocument(context, uri)
|
||||||
|
}
|
||||||
|
return getDataColumn(context, uri, null, null)
|
||||||
|
}
|
||||||
|
"file".equals(uri.scheme, ignoreCase = true) -> {
|
||||||
|
return uri.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleMediaDocument(context: Context, uri: Uri): String? {
|
||||||
|
val docId = DocumentsContract.getDocumentId(uri)
|
||||||
|
val split = docId.split(":").toTypedArray()
|
||||||
|
val type = split[0]
|
||||||
|
var contentUri: Uri? = null
|
||||||
|
when (type) {
|
||||||
|
"image" -> {
|
||||||
|
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||||
|
}
|
||||||
|
"video" -> {
|
||||||
|
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
||||||
|
}
|
||||||
|
"audio" -> {
|
||||||
|
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val selection = "_id=?"
|
||||||
|
val selectionArgs = arrayOf(split[1])
|
||||||
|
return getDataColumn(
|
||||||
|
context,
|
||||||
|
contentUri,
|
||||||
|
selection,
|
||||||
|
selectionArgs
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleDownloadsDocument(context: Context, uri: Uri): String? {
|
||||||
|
val fileName = getFilePath(context, uri)
|
||||||
|
if (fileName != null) {
|
||||||
|
return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
|
||||||
|
}
|
||||||
|
var id = DocumentsContract.getDocumentId(uri)
|
||||||
|
if (id.startsWith("raw:")) {
|
||||||
|
id = id.replaceFirst("raw:".toRegex(), "")
|
||||||
|
val file = File(id)
|
||||||
|
if (file.exists()) return id
|
||||||
|
}
|
||||||
|
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
|
||||||
|
return getDataColumn(context, contentUri, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleExternalStorageDocument(context: Context, uri: Uri): String {
|
||||||
|
val docId: String = if (DocumentsContract.isDocumentUri(context, uri)) {
|
||||||
|
DocumentsContract.getDocumentId(uri)
|
||||||
|
} else {
|
||||||
|
// please please please PLEASE let this be the only other case
|
||||||
|
DocumentsContract.getTreeDocumentId(uri)
|
||||||
|
}
|
||||||
|
val split = docId.split(":").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 {
|
||||||
|
"storage" + "/" + docId.replace(":", "/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun getFilePath(context: Context, uri: Uri?): String? {
|
||||||
|
var cursor: Cursor? = null
|
||||||
|
val projection = arrayOf(
|
||||||
|
MediaStore.MediaColumns.DISPLAY_NAME
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
if (uri == null) return null
|
||||||
|
cursor = context.contentResolver.query(
|
||||||
|
uri, projection, null, null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
val index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)
|
||||||
|
val data = cursor.getString(index)
|
||||||
|
cursor.close()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
cursor?.close()
|
||||||
|
} finally {
|
||||||
|
cursor?.close()
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
if (uri == null) return null
|
||||||
|
cursor = context.contentResolver.query(
|
||||||
|
uri, projection, selection, selectionArgs,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
val index = cursor.getColumnIndexOrThrow(column)
|
||||||
|
val data = cursor.getString(index)
|
||||||
|
cursor.close()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,69 +1,74 @@
|
|||||||
package com.geode.launcher.utils
|
package com.geode.launcher.utils
|
||||||
|
|
||||||
import android.app.Activity
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.ContentUris
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.database.Cursor
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
|
||||||
import android.provider.DocumentsContract
|
import android.provider.DocumentsContract
|
||||||
import android.provider.MediaStore
|
|
||||||
import android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
|
||||||
import android.provider.OpenableColumns
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.FileProvider
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import com.geode.launcher.activityresult.GeodeOpenFileActivityResult
|
||||||
|
import com.geode.launcher.activityresult.GeodeOpenFilesActivityResult
|
||||||
|
import com.geode.launcher.activityresult.GeodeSaveFileActivityResult
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.net.URI
|
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object GeodeUtils {
|
object GeodeUtils {
|
||||||
private lateinit var activity: WeakReference<AppCompatActivity>
|
private lateinit var activity: WeakReference<AppCompatActivity>
|
||||||
private lateinit var fileResultLauncher: ActivityResultLauncher<Intent>
|
private lateinit var openFileResultLauncher: ActivityResultLauncher<GeodeOpenFileActivityResult.OpenFileParams>
|
||||||
private lateinit var filesResultLauncher: ActivityResultLauncher<Intent>
|
private lateinit var openDirectoryResultLauncher: ActivityResultLauncher<Uri?>
|
||||||
|
private lateinit var openFilesResultLauncher: ActivityResultLauncher<GeodeOpenFilesActivityResult.OpenFileParams>
|
||||||
|
private lateinit var saveFileResultLauncher: ActivityResultLauncher<GeodeSaveFileActivityResult.SaveFileParams>
|
||||||
|
|
||||||
fun setContext(activity: AppCompatActivity) {
|
fun setContext(activity: AppCompatActivity) {
|
||||||
this.activity = WeakReference(activity)
|
this.activity = WeakReference(activity)
|
||||||
fileResultLauncher = activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
openFileResultLauncher = activity.registerForActivityResult(GeodeOpenFileActivityResult()) { uri ->
|
||||||
if (result.resultCode == Activity.RESULT_OK) {
|
if (uri != null) {
|
||||||
val data = result.data
|
val path = FileUtils.getRealPathFromURI(activity, uri)
|
||||||
if (data != null) {
|
if (path != null) {
|
||||||
val uri = data.data
|
selectFileCallback(path)
|
||||||
if (uri != null) {
|
return@registerForActivityResult
|
||||||
val path = getRealPathFromURI(activity, uri)
|
|
||||||
if (path != null) {
|
|
||||||
selectFileCallback(path)
|
|
||||||
return@registerForActivityResult
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
failedCallback()
|
failedCallback()
|
||||||
}
|
}
|
||||||
filesResultLauncher = activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
openDirectoryResultLauncher = activity.registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
|
||||||
if (result.resultCode == Activity.RESULT_OK) {
|
if (it != null) {
|
||||||
val data = result.data
|
val path = FileUtils.getRealPathFromURI(activity, it)
|
||||||
if (data != null) {
|
if (path != null)
|
||||||
val clipData = data.clipData
|
selectFileCallback(path)
|
||||||
if (clipData != null) {
|
return@registerForActivityResult
|
||||||
val paths = Array(clipData.itemCount) { "" }
|
}
|
||||||
for (i in 0 until clipData.itemCount) {
|
failedCallback()
|
||||||
val path = getRealPathFromURI(activity, clipData.getItemAt(i).uri)
|
}
|
||||||
if (path != null) {
|
openFilesResultLauncher = activity.registerForActivityResult(GeodeOpenFilesActivityResult()) { result ->
|
||||||
paths[i] = path
|
if (result.isEmpty()) {
|
||||||
}
|
failedCallback()
|
||||||
}
|
return@registerForActivityResult
|
||||||
selectFilesCallback(paths)
|
}
|
||||||
return@registerForActivityResult
|
val paths: Array<String> = Array(result.size) {"n = $it"}
|
||||||
}
|
for (i in result.indices) {
|
||||||
|
val path = FileUtils.getRealPathFromURI(activity, result[i])
|
||||||
|
if (path != null) {
|
||||||
|
paths[i] = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectFilesCallback(paths)
|
||||||
|
return@registerForActivityResult
|
||||||
|
}
|
||||||
|
saveFileResultLauncher = activity.registerForActivityResult(GeodeSaveFileActivityResult()) { uri ->
|
||||||
|
if (uri != null) {
|
||||||
|
val path = FileUtils.getRealPathFromURI(activity, uri)
|
||||||
|
if (path != null) {
|
||||||
|
selectFileCallback(path)
|
||||||
|
return@registerForActivityResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
failedCallback()
|
failedCallback()
|
||||||
@@ -72,16 +77,13 @@ object GeodeUtils {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getLogcatCrashBuffer(): String {
|
fun getLogcatCrashBuffer(): String {
|
||||||
try {
|
return try {
|
||||||
val logcatProcess = Runtime.getRuntime().exec("logcat -v brief -b crash -d")
|
val logcatProcess = Runtime.getRuntime().exec("logcat -v brief -b crash -d")
|
||||||
|
|
||||||
val logcatOutput = logcatProcess.inputStream.bufferedReader().readText()
|
logcatProcess.inputStream.bufferedReader().readText()
|
||||||
|
} catch (e: Exception) {
|
||||||
return logcatOutput
|
|
||||||
}
|
|
||||||
catch (e: Exception) {
|
|
||||||
Log.e("Geode", "Failed to get logcat crash buffer", e)
|
Log.e("Geode", "Failed to get logcat crash buffer", e)
|
||||||
return ""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,18 +113,19 @@ object GeodeUtils {
|
|||||||
activity.get()?.run {
|
activity.get()?.run {
|
||||||
packageManager.getLaunchIntentForPackage(packageName)?.also {
|
packageManager.getLaunchIntentForPackage(packageName)?.also {
|
||||||
val mainIntent = Intent.makeRestartActivityTask(it.component)
|
val mainIntent = Intent.makeRestartActivityTask(it.component)
|
||||||
mainIntent.putExtra("restarted", true);
|
mainIntent.putExtra("restarted", true)
|
||||||
startActivity(mainIntent)
|
startActivity(mainIntent)
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO As of now this is unused
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun openFolder(path: String): Boolean {
|
fun openFolder(path: String): Boolean {
|
||||||
activity.get()?.run {
|
activity.get()?.run {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
DocumentFile.fromFile(File(path)).also {
|
DocumentFile.fromFile(File(path)).also {
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, it.uri)
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, it.uri)
|
||||||
@@ -137,28 +140,27 @@ object GeodeUtils {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("KotlinJniMissingFunction")
|
||||||
external fun selectFileCallback(path: String)
|
external fun selectFileCallback(path: String)
|
||||||
|
|
||||||
|
@Suppress("KotlinJniMissingFunction")
|
||||||
external fun selectFilesCallback(paths: Array<String>)
|
external fun selectFilesCallback(paths: Array<String>)
|
||||||
|
|
||||||
|
@Suppress("KotlinJniMissingFunction")
|
||||||
external fun failedCallback()
|
external fun failedCallback()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun selectFile(path: String): Boolean {
|
fun selectFile(path: String): Boolean {
|
||||||
activity.get()?.run {
|
activity.get()?.run {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
var uri: Uri?
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
DocumentFile.fromFile(File(path)).also {
|
DocumentFile.fromFile(File(path)).also {
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, it.uri)
|
uri = it.uri
|
||||||
}
|
}
|
||||||
intent.setType("*/*")
|
try {
|
||||||
|
openFileResultLauncher.launch(GeodeOpenFileActivityResult.OpenFileParams(arrayOf("*/*"), uri))
|
||||||
if (intent.resolveActivity(packageManager) != null) {
|
|
||||||
print("Geode Selectfile")
|
|
||||||
fileResultLauncher.launch(intent)
|
|
||||||
print("Geode launched ")
|
|
||||||
return true
|
return true
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -167,18 +169,15 @@ object GeodeUtils {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun selectFiles(path: String): Boolean {
|
fun selectFiles(path: String): Boolean {
|
||||||
activity.get()?.run {
|
activity.get()?.run {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
var uri: Uri?
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
DocumentFile.fromFile(File(path)).also {
|
DocumentFile.fromFile(File(path)).also {
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, it.uri)
|
uri = it.uri
|
||||||
}
|
}
|
||||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
try {
|
||||||
intent.setType("*/*")
|
openFilesResultLauncher.launch(GeodeOpenFilesActivityResult.OpenFileParams(arrayOf("*/*"), uri))
|
||||||
|
|
||||||
if (intent.resolveActivity(packageManager) != null) {
|
|
||||||
filesResultLauncher.launch(intent)
|
|
||||||
return true
|
return true
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -187,17 +186,15 @@ object GeodeUtils {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun selectFolder(path: String): Boolean {
|
fun selectFolder(path: String): Boolean {
|
||||||
activity.get()?.run {
|
activity.get()?.run {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
var uri: Uri?
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
DocumentFile.fromFile(File(path)).also {
|
DocumentFile.fromFile(File(path)).also {
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, it.uri)
|
uri = it.uri
|
||||||
}
|
}
|
||||||
intent.setType("*/*")
|
try {
|
||||||
|
openDirectoryResultLauncher.launch(uri)
|
||||||
if (intent.resolveActivity(packageManager) != null) {
|
|
||||||
fileResultLauncher.launch(intent)
|
|
||||||
return true
|
return true
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -206,17 +203,16 @@ object GeodeUtils {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun createFile(path: String): Boolean {
|
fun createFile(path: String): Boolean {
|
||||||
activity.get()?.run {
|
activity.get()?.run {
|
||||||
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
var uri: Uri?
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
DocumentFile.fromFile(File(path)).also {
|
DocumentFile.fromFile(File(path)).also {
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, it.uri)
|
uri = it.uri
|
||||||
}
|
}
|
||||||
intent.setType("*/*")
|
|
||||||
|
|
||||||
if (intent.resolveActivity(packageManager) != null) {
|
try {
|
||||||
fileResultLauncher.launch(intent)
|
saveFileResultLauncher.launch(GeodeSaveFileActivityResult.SaveFileParams(null, uri))
|
||||||
return true
|
return true
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -250,154 +246,6 @@ object GeodeUtils {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// copied from https://stackoverflow.com/questions/17546101/get-real-path-for-uri-android
|
|
||||||
// i am actually very lazy to move this to a separate class
|
|
||||||
|
|
||||||
fun getRealPathFromURI(context: Context, uri: Uri): String? {
|
|
||||||
when {
|
|
||||||
// DocumentProvider
|
|
||||||
DocumentsContract.isDocumentUri(context, uri) -> {
|
|
||||||
when {
|
|
||||||
// ExternalStorageProvider
|
|
||||||
isExternalStorageDocument(uri) -> {
|
|
||||||
val docId = DocumentsContract.getDocumentId(uri)
|
|
||||||
val split = docId.split(":").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 {
|
|
||||||
"storage" + "/" + docId.replace(":", "/")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isDownloadsDocument(uri) -> {
|
|
||||||
val fileName = getFilePath(context, uri)
|
|
||||||
if (fileName != null) {
|
|
||||||
return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
|
|
||||||
}
|
|
||||||
var id = DocumentsContract.getDocumentId(uri)
|
|
||||||
if (id.startsWith("raw:")) {
|
|
||||||
id = id.replaceFirst("raw:".toRegex(), "")
|
|
||||||
val file = File(id)
|
|
||||||
if (file.exists()) return id
|
|
||||||
}
|
|
||||||
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
|
|
||||||
return getDataColumn(context, contentUri, null, null)
|
|
||||||
}
|
|
||||||
isMediaDocument(uri) -> {
|
|
||||||
val docId = DocumentsContract.getDocumentId(uri)
|
|
||||||
val split = docId.split(":").toTypedArray()
|
|
||||||
val type = split[0]
|
|
||||||
var contentUri: Uri? = null
|
|
||||||
when (type) {
|
|
||||||
"image" -> {
|
|
||||||
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
|
||||||
}
|
|
||||||
"video" -> {
|
|
||||||
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
|
||||||
}
|
|
||||||
"audio" -> {
|
|
||||||
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val selection = "_id=?"
|
|
||||||
val selectionArgs = arrayOf(split[1])
|
|
||||||
return getDataColumn(context, contentUri, selection, selectionArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: add the geode provider
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"content".equals(uri.scheme, ignoreCase = true) -> {
|
|
||||||
// Return the remote address
|
|
||||||
if (isGooglePhotosUri(uri)) return uri.lastPathSegment
|
|
||||||
return getDataColumn(context, uri, null, null)
|
|
||||||
}
|
|
||||||
"file".equals(uri.scheme, ignoreCase = true) -> {
|
|
||||||
return uri.path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDataColumn(context: Context, uri: Uri?, selection: String?,
|
|
||||||
selectionArgs: Array<String>?): String? {
|
|
||||||
var cursor: Cursor? = null
|
|
||||||
val column = "_data"
|
|
||||||
val projection = arrayOf(
|
|
||||||
column
|
|
||||||
)
|
|
||||||
try {
|
|
||||||
if (uri == null) return null
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun getFilePath(context: Context, uri: Uri?): String? {
|
|
||||||
var cursor: Cursor? = null
|
|
||||||
val projection = arrayOf(
|
|
||||||
MediaStore.MediaColumns.DISPLAY_NAME
|
|
||||||
)
|
|
||||||
try {
|
|
||||||
if (uri == null) return null
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
fun isGooglePhotosUri(uri: Uri): Boolean {
|
|
||||||
return "com.google.android.apps.photos.content" == uri.authority
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isGeodeUri(uri: Uri): Boolean {
|
fun isGeodeUri(uri: Uri): Boolean {
|
||||||
return "com.geode.launcher.user" == uri.authority
|
return "com.geode.launcher.user" == uri.authority
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user