android: the handoff — the pending rounds, the pipeline, and what is unverified
Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
This commit is contained in:
1 parent
867fd42972
commit
9f0601027c
400 files changed
+26401
-3
No files matched your search
@@ -0,0 +1,76 @@
|
||||
package com.soulstream.transfernotice
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import app.tauri.annotation.Command
|
||||
import app.tauri.annotation.InvokeArg
|
||||
import app.tauri.annotation.TauriPlugin
|
||||
import app.tauri.plugin.Invoke
|
||||
import app.tauri.plugin.JSObject
|
||||
import app.tauri.plugin.Plugin
|
||||
|
||||
/** What the notice says — the Rust `TransferNotice`, camelCase. */
|
||||
@InvokeArg
|
||||
class NoticeArgs {
|
||||
/** how many files are still in flight; zero means take the notice down */
|
||||
var count: Int = 0
|
||||
var title: String? = null
|
||||
var line: String? = null
|
||||
var percent: Int = 0
|
||||
/** nobody has stated a size yet, so the bar has no end to walk towards */
|
||||
var indeterminate: Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* The bridge between the WebView and the service that owns the notice.
|
||||
* `update` mirrors what Save is fetching (and starts the service the first
|
||||
* time); `clear` takes the notice down. Its buttons come back as the plugin
|
||||
* event `action` with `{ action }` — "cancel" or "open".
|
||||
*/
|
||||
@TauriPlugin
|
||||
class TransferNoticePlugin(private val activity: Activity) : Plugin(activity) {
|
||||
private var askedForNotifications = false
|
||||
|
||||
init {
|
||||
TransferHub.onAction = { action ->
|
||||
val payload = JSObject()
|
||||
payload.put("action", action)
|
||||
trigger("action", payload)
|
||||
}
|
||||
/* the channel exists from app start, so a user can silence the
|
||||
downloads on their own before the first one ever runs */
|
||||
TransferHub.ensureChannel(activity.applicationContext)
|
||||
}
|
||||
|
||||
@Command
|
||||
fun update(invoke: Invoke) {
|
||||
val args = invoke.parseArgs(NoticeArgs::class.java)
|
||||
ensureNotificationPermission()
|
||||
TransferHub.update(activity.applicationContext, args)
|
||||
invoke.resolve()
|
||||
}
|
||||
|
||||
@Command
|
||||
fun clear(invoke: Invoke) {
|
||||
TransferHub.clear(activity.applicationContext)
|
||||
invoke.resolve()
|
||||
}
|
||||
|
||||
/** Android 13+: the notice is a notification and needs the permission;
|
||||
* asked once, the first time something is fetched. Its own request code
|
||||
* — 4711 is the media card's, and two requests that share one would
|
||||
* answer each other. The service runs either way; without the
|
||||
* permission it simply has nothing to show. */
|
||||
private fun ensureNotificationPermission() {
|
||||
if (Build.VERSION.SDK_INT < 33 || askedForNotifications) return
|
||||
askedForNotifications = true
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.POST_NOTIFICATIONS)
|
||||
== PackageManager.PERMISSION_GRANTED
|
||||
) return
|
||||
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 4712)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user