nx: support multi-share API
parent
183de24e62
commit
680322d916
|
@ -55,8 +55,7 @@ class NativeX(private val mCtx: MainActivity) {
|
||||||
val IMAGE_FULL = Regex("^/image/full/[0-9a-f]+$")
|
val IMAGE_FULL = Regex("^/image/full/[0-9a-f]+$")
|
||||||
|
|
||||||
val SHARE_URL = Regex("^/api/share/url/.+$")
|
val SHARE_URL = Regex("^/api/share/url/.+$")
|
||||||
val SHARE_BLOB = Regex("^/api/share/blob/.+$")
|
val SHARE_BLOB = Regex("^/api/share/blobs$")
|
||||||
val SHARE_LOCAL = Regex("^/api/share/local/[0-9a-f]+$")
|
|
||||||
|
|
||||||
val CONFIG_ALLOW_MEDIA = Regex("^/api/config/allow_media/\\d+$")
|
val CONFIG_ALLOW_MEDIA = Regex("^/api/config/allow_media/\\d+$")
|
||||||
}
|
}
|
||||||
|
@ -113,6 +112,12 @@ class NativeX(private val mCtx: MainActivity) {
|
||||||
dlService!!.queue(url, filename)
|
dlService!!.queue(url, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
fun setShareBlobs(objects: String?) {
|
||||||
|
if (objects == null) return;
|
||||||
|
dlService!!.setShareBlobs(JSONArray(objects))
|
||||||
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
fun playVideo(auid: String, fileid: Long, urlsArray: String) {
|
fun playVideo(auid: String, fileid: Long, urlsArray: String) {
|
||||||
mCtx.threadPool.submit {
|
mCtx.threadPool.submit {
|
||||||
|
@ -250,9 +255,7 @@ class NativeX(private val mCtx: MainActivity) {
|
||||||
} else if (path.matches(API.SHARE_URL)) {
|
} else if (path.matches(API.SHARE_URL)) {
|
||||||
makeResponse(dlService!!.shareUrl(URLDecoder.decode(parts[4], "UTF-8")))
|
makeResponse(dlService!!.shareUrl(URLDecoder.decode(parts[4], "UTF-8")))
|
||||||
} else if (path.matches(API.SHARE_BLOB)) {
|
} else if (path.matches(API.SHARE_BLOB)) {
|
||||||
makeResponse(dlService!!.shareBlobFromUrl(URLDecoder.decode(parts[4], "UTF-8")))
|
makeResponse(dlService!!.shareBlobs())
|
||||||
} else if (path.matches(API.SHARE_LOCAL)) {
|
|
||||||
makeResponse(dlService!!.shareLocal(parts[4]))
|
|
||||||
} else if (path.matches(API.CONFIG_ALLOW_MEDIA)) {
|
} else if (path.matches(API.CONFIG_ALLOW_MEDIA)) {
|
||||||
permissions.setAllowMedia(true)
|
permissions.setAllowMedia(true)
|
||||||
if (permissions.requestMediaPermissionSync()) {
|
if (permissions.requestMediaPermissionSync()) {
|
||||||
|
|
|
@ -6,14 +6,15 @@ import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.webkit.CookieManager
|
import android.webkit.CookieManager
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.collection.ArrayMap
|
import androidx.collection.ArrayMap
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import org.json.JSONArray
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
|
||||||
@UnstableApi class DownloadService(private val mActivity: AppCompatActivity, private val query: TimelineQuery) {
|
@UnstableApi class DownloadService(private val mActivity: AppCompatActivity, private val query: TimelineQuery) {
|
||||||
private val mDownloads: MutableMap<Long, () -> Unit> = ArrayMap()
|
private val mDownloads: MutableMap<Long, () -> Unit> = ArrayMap()
|
||||||
|
private var mShareBlobs: JSONArray? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback when download is complete
|
* Callback when download is complete
|
||||||
|
@ -31,8 +32,6 @@ import java.util.concurrent.CountDownLatch
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast.makeText(mActivity, "Download Complete", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,48 +76,68 @@ import java.util.concurrent.CountDownLatch
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Share a URL as a blob
|
* Share the blobs from URLs already set by setShareBlobs
|
||||||
* @param url The URL to share
|
|
||||||
* @return True if the URL was shared
|
* @return True if the URL was shared
|
||||||
*/
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun shareBlobFromUrl(url: String): Boolean {
|
fun shareBlobs(): Boolean {
|
||||||
val id = queue(url, "")
|
if (mShareBlobs == null) throw Exception("No blobs to share")
|
||||||
val latch = CountDownLatch(1)
|
|
||||||
|
// All URIs to share including remote and local files
|
||||||
|
val uris = ArrayList<Uri>()
|
||||||
|
val dlIds = ArrayList<Long>()
|
||||||
|
|
||||||
|
// Process all objects to share
|
||||||
|
for (i in 0 until mShareBlobs!!.length()) {
|
||||||
|
val obj = mShareBlobs!!.getJSONObject(i)
|
||||||
|
|
||||||
|
// If AUID is found, then look for local file
|
||||||
|
val auid = obj.getString("auid")
|
||||||
|
if (auid != "") {
|
||||||
|
val sysImgs = query.getSystemImagesByAUIDs(listOf(auid))
|
||||||
|
if (sysImgs.isNotEmpty()) {
|
||||||
|
uris.add(sysImgs[0].uri)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue a download for remote files
|
||||||
|
dlIds.add(queue(obj.getString("href"), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all downloads to complete
|
||||||
|
val latch = CountDownLatch(dlIds.size)
|
||||||
synchronized(mDownloads) {
|
synchronized(mDownloads) {
|
||||||
mDownloads.put(id, fun() { latch.countDown() })
|
for (dlId in dlIds) {
|
||||||
|
mDownloads.put(dlId, fun() { latch.countDown() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
latch.await()
|
latch.await()
|
||||||
|
|
||||||
// Get the URI of the downloaded file
|
// Get the URI of the downloaded file
|
||||||
|
for (id in dlIds) {
|
||||||
val sUri = getDownloadedFileURI(id) ?: throw Exception("Failed to download file")
|
val sUri = getDownloadedFileURI(id) ?: throw Exception("Failed to download file")
|
||||||
val uri = Uri.parse(sUri)
|
uris.add(Uri.parse(sUri))
|
||||||
|
}
|
||||||
|
|
||||||
// Create sharing intent
|
// Create sharing intent
|
||||||
val intent = Intent(Intent.ACTION_SEND)
|
val intent = Intent(Intent.ACTION_SEND_MULTIPLE)
|
||||||
intent.type = mActivity.contentResolver.getType(uri)
|
intent.type = "*/*"
|
||||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
intent.putExtra(Intent.EXTRA_STREAM, uris)
|
||||||
mActivity.startActivity(Intent.createChooser(intent, null))
|
mActivity.startActivity(Intent.createChooser(intent, null))
|
||||||
|
|
||||||
|
// Reset the blobs
|
||||||
|
mShareBlobs = null
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Share a local image
|
* Set the blobs to share
|
||||||
* @param auid The AUID of the image to share
|
* @param objects The blobs to share
|
||||||
* @return True if the image was shared
|
|
||||||
*/
|
*/
|
||||||
@Throws(Exception::class)
|
fun setShareBlobs(objects: JSONArray) {
|
||||||
fun shareLocal(auid: String): Boolean {
|
mShareBlobs = objects
|
||||||
val sysImgs = query.getSystemImagesByAUIDs(listOf(auid))
|
|
||||||
if (sysImgs.isEmpty()) throw Exception("Image not found locally")
|
|
||||||
val uri = sysImgs[0].uri
|
|
||||||
|
|
||||||
val intent = Intent(Intent.ACTION_SEND)
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
intent.type = mActivity.contentResolver.getType(uri)
|
|
||||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
|
||||||
mActivity.startActivity(Intent.createChooser(intent, null))
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue