@craft-native/android 0.0.225 → 0.0.226
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -120,6 +120,7 @@ internal class CraftNativeServices(
|
|
|
120
120
|
done(success(CraftNativeMedia.prune(context, (0 until keep.length()).map { keep.optString(it) })))
|
|
121
121
|
}
|
|
122
122
|
"usage" -> done(success(CraftNativeMedia.usage(context)))
|
|
123
|
+
"clear" -> done(success(CraftNativeMedia.clear(context)))
|
|
123
124
|
else -> done(failure("UNKNOWN_ACTION", "Unsupported Media method"))
|
|
124
125
|
}
|
|
125
126
|
"Background" -> {
|
|
@@ -1021,7 +1021,8 @@ internal object CraftNativeSymbols {
|
|
|
1021
1021
|
* A native Video given an address with a copy here plays the copy.
|
|
1022
1022
|
*/
|
|
1023
1023
|
internal object CraftNativeMedia {
|
|
1024
|
-
private val
|
|
1024
|
+
private data class Flight(val id: String, val waiting: MutableList<(CraftNativeCapabilityResult) -> Unit>)
|
|
1025
|
+
private val inFlight = HashMap<String, Flight>()
|
|
1025
1026
|
private val executor = Executors.newFixedThreadPool(2)
|
|
1026
1027
|
private val main = Handler(Looper.getMainLooper())
|
|
1027
1028
|
|
|
@@ -1054,12 +1055,12 @@ internal object CraftNativeMedia {
|
|
|
1054
1055
|
if (!cellular && metered(context)) {
|
|
1055
1056
|
return done(CraftNativeCapabilityResult(data = JSONObject().put("ok", false).put("url", address).put("reason", "cellular")))
|
|
1056
1057
|
}
|
|
1057
|
-
synchronized(inFlight) {
|
|
1058
|
+
val flight = synchronized(inFlight) {
|
|
1058
1059
|
inFlight[address]?.let { waiting ->
|
|
1059
|
-
waiting.add(done)
|
|
1060
|
+
waiting.waiting.add(done)
|
|
1060
1061
|
return
|
|
1061
1062
|
}
|
|
1062
|
-
inFlight[address] =
|
|
1063
|
+
Flight(java.util.UUID.randomUUID().toString(), mutableListOf(done)).also { inFlight[address] = it }
|
|
1063
1064
|
}
|
|
1064
1065
|
executor.execute {
|
|
1065
1066
|
val result = runCatching {
|
|
@@ -1073,7 +1074,7 @@ internal object CraftNativeMedia {
|
|
|
1073
1074
|
val target = file(context, address)
|
|
1074
1075
|
target.parentFile?.mkdirs()
|
|
1075
1076
|
// Written aside and moved into place, so a half-written file is never played.
|
|
1076
|
-
val staging = File(target.parentFile, "${target.name}.part")
|
|
1077
|
+
val staging = File(target.parentFile, "${target.name}.${flight.id}.part")
|
|
1077
1078
|
try {
|
|
1078
1079
|
val size = connection.inputStream.use { input -> staging.outputStream().use { input.copyTo(it) } }
|
|
1079
1080
|
val expected = connection.contentLengthLong
|
|
@@ -1081,6 +1082,9 @@ internal object CraftNativeMedia {
|
|
|
1081
1082
|
return@runCatching CraftNativeCapabilityResult(code = "NETWORK_ERROR", message = "media.keep received an incomplete file")
|
|
1082
1083
|
}
|
|
1083
1084
|
synchronized(inFlight) {
|
|
1085
|
+
if (inFlight[address]?.id != flight.id) {
|
|
1086
|
+
return@runCatching CraftNativeCapabilityResult(code = "CANCELLED", message = "The video cache was cleared")
|
|
1087
|
+
}
|
|
1084
1088
|
if (!staging.renameTo(target)) {
|
|
1085
1089
|
return@runCatching CraftNativeCapabilityResult(code = "IO_ERROR", message = "media.keep could not store the file")
|
|
1086
1090
|
}
|
|
@@ -1098,7 +1102,7 @@ internal object CraftNativeMedia {
|
|
|
1098
1102
|
}
|
|
1099
1103
|
CraftNativeCapabilityResult(code = if (full) "NO_SPACE" else if (error is java.net.SocketTimeoutException) "TIMEOUT" else "NETWORK_ERROR", message = error.message ?: "media.keep failed")
|
|
1100
1104
|
}
|
|
1101
|
-
val waiting = synchronized(inFlight) { inFlight.remove(address)
|
|
1105
|
+
val waiting = synchronized(inFlight) { if (inFlight[address]?.id == flight.id) inFlight.remove(address)?.waiting.orEmpty() else emptyList() }
|
|
1102
1106
|
main.post { waiting.forEach { it(result) } }
|
|
1103
1107
|
}
|
|
1104
1108
|
}
|
|
@@ -1115,12 +1119,31 @@ internal object CraftNativeMedia {
|
|
|
1115
1119
|
var removed = 0
|
|
1116
1120
|
synchronized(inFlight) {
|
|
1117
1121
|
// A concurrent keep owns its target and staging file until it finishes.
|
|
1118
|
-
val active = inFlight.
|
|
1122
|
+
val active = inFlight.flatMap { (address, flight) ->
|
|
1123
|
+
val name = file(context, address).name
|
|
1124
|
+
listOf(name, "$name.${flight.id}.part")
|
|
1125
|
+
}.toSet()
|
|
1126
|
+
root(context).listFiles()?.forEach { file ->
|
|
1127
|
+
if (file.name !in active && file.name !in wanted && file.delete()) removed++
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
return removed
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
/** Invalidates old transfers before deleting files; a later keep starts afresh. */
|
|
1134
|
+
fun clear(context: Context): Int {
|
|
1135
|
+
var removed = 0
|
|
1136
|
+
var failure: java.io.IOException? = null
|
|
1137
|
+
val waiting = synchronized(inFlight) {
|
|
1138
|
+
val callbacks = inFlight.values.flatMap { it.waiting }
|
|
1139
|
+
inFlight.clear()
|
|
1119
1140
|
root(context).listFiles()?.forEach { file ->
|
|
1120
|
-
|
|
1121
|
-
if (target !in active && file.name !in wanted && file.delete()) removed++
|
|
1141
|
+
if (file.delete()) removed++ else failure = java.io.IOException("The video cache could not be cleared")
|
|
1122
1142
|
}
|
|
1143
|
+
callbacks
|
|
1123
1144
|
}
|
|
1145
|
+
main.post { waiting.forEach { it(CraftNativeCapabilityResult(code = "CANCELLED", message = "The video cache was cleared")) } }
|
|
1146
|
+
failure?.let { throw it }
|
|
1124
1147
|
return removed
|
|
1125
1148
|
}
|
|
1126
1149
|
|
|
@@ -4091,6 +4091,7 @@ class MainActivity : AppCompatActivity() {
|
|
|
4091
4091
|
show(target)
|
|
4092
4092
|
} else {
|
|
4093
4093
|
host.removeView(target.view)
|
|
4094
|
+
target.view.translationX = 0f
|
|
4094
4095
|
current.view.translationX = 0f
|
|
4095
4096
|
chrome?.selectTab(currentTab)
|
|
4096
4097
|
tabSwipeTarget = null
|
|
@@ -4504,6 +4505,11 @@ class MainActivity : AppCompatActivity() {
|
|
|
4504
4505
|
* screen shown before hears true (its `navigation.onAppear`).
|
|
4505
4506
|
*/
|
|
4506
4507
|
private fun show(screen: Screen) {
|
|
4508
|
+
// A retained tab may have been the offscreen preview of a cancelled
|
|
4509
|
+
// swipe, or the outgoing view of a completed swipe. Its animator can
|
|
4510
|
+
// finish after the peer animator, so clear that ownership on display.
|
|
4511
|
+
screen.view.animate().withEndAction(null).setListener(null).cancel()
|
|
4512
|
+
screen.view.translationX = 0f
|
|
4507
4513
|
// A navigation breadcrumb: the trail a crash report carries.
|
|
4508
4514
|
if (visibleScreen !== screen) CraftCrashReporter.screenAppeared(screen.route ?: "home")
|
|
4509
4515
|
val bars = chrome
|