Generate SSD browser dialog buttons from typed Jerboa

ober

217adb768a60d557016aebe6271564d18df0260c

diff --git a/.build.yml b/.build.yml
index a64e187..141842b 100644
--- a/.build.yml
+++ b/.build.yml
@@ -5,7 +5,7 @@ packages:
   - make=4.4.1-r4
 sources:
   # Build dependency: full immutable commit, mirrored in dependencies.lock.json.
-  - "https://git.sr.ht/~lisp/jerboa#035ee76dd63f2402a3cd9501d4485e081c66dbb3"
+  - "https://git.sr.ht/~lisp/jerboa#7765fea05df47999d154b15211e779affcdc237a"
   # The second source is the build subject selected by the SourceHut submitter.
   - https://git.sr.ht/~lisp/jerboa-android
 tasks:
@@ -14,6 +14,6 @@ tasks:
       test "$(apk info -v chez-scheme)" = chez-scheme-10.3.0-r2
       test "$(apk info -v git)" = git-2.54.0-r0
       test "$(apk info -v make)" = make-4.4.1-r4
-      test "$(git -C ../jerboa rev-parse HEAD)" = 035ee76dd63f2402a3cd9501d4485e081c66dbb3
-      test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = 3aa2b2c5769a308f6ab616ca6e0b7d78c41014a9
+      test "$(git -C ../jerboa rev-parse HEAD)" = 7765fea05df47999d154b15211e779affcdc237a
+      test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = 223a197c469afc20dcc7697ed892213f4baa0723
       JERBOA="chez --libdirs .:../jerboa/lib --script" make test
diff --git a/dependencies.lock.json b/dependencies.lock.json
index 80a656d..174c543 100644
--- a/dependencies.lock.json
+++ b/dependencies.lock.json
@@ -11,8 +11,8 @@
   "generator_runtime": {
     "name": "jerboa",
     "repository": "https://git.sr.ht/~lisp/jerboa",
-    "commit": "035ee76dd63f2402a3cd9501d4485e081c66dbb3",
-    "tree": "3aa2b2c5769a308f6ab616ca6e0b7d78c41014a9"
+    "commit": "7765fea05df47999d154b15211e779affcdc237a",
+    "tree": "223a197c469afc20dcc7697ed892213f4baa0723"
   },
   "assurance_tools": {
     "osv_scanner": {
diff --git a/scripts/verify-supply-chain.sh b/scripts/verify-supply-chain.sh
index 3b971e1..383ec6f 100755
--- a/scripts/verify-supply-chain.sh
+++ b/scripts/verify-supply-chain.sh
@@ -3,8 +3,8 @@ set -eu
 
 repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P)
 lock="$repo/dependencies.lock.json"
-jerboa_commit=035ee76dd63f2402a3cd9501d4485e081c66dbb3 # gitsafe:ignore
-jerboa_tree=3aa2b2c5769a308f6ab616ca6e0b7d78c41014a9 # gitsafe:ignore
+jerboa_commit=7765fea05df47999d154b15211e779affcdc237a # gitsafe:ignore
+jerboa_tree=223a197c469afc20dcc7697ed892213f4baa0723 # gitsafe:ignore
 gradle_sha=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78
 jdk_macos_sha=8fa1eff40bb637a33613b2ccb8b12c70dc3661cc22cf8e784943715769a05336
 jdk_linux_sha=d8afc263758141a66e0e3aafc321e783f7016696f4eaea067d340a269037d331
diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 8a16883..3517397 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -4698,7 +4698,9 @@
                       (java io InputStream)
                       (java io OutputStream)
                       (android app AlertDialog)
+                      (android app AlertDialog Builder)
                       (android content Context)
+                      (android content DialogInterface)
                       (android graphics Bitmap)
                       (android content Intent)
                       (android database Cursor)
@@ -4811,6 +4813,11 @@
                 mainActivitySetPageIndex mainActivitySetPdfIdentity
                 mainActivitySetLoadedPdfState
                 mainActivityAdvanceLoadGeneration
+                mainActivitySetPositiveChooseSsdPdfFolder
+                mainActivitySetNeutralChooseSsdPdfFolder
+                mainActivitySetPositiveOpenAnyPdf
+                mainActivitySetNegativeOpenAnyPdf
+                mainActivitySetPositiveRequestDownloadAccess
                 mainActivityRotateReviewPage
                 mainActivitySeedBundledTruthAsync
                 mainActivityHandleAreaSelectionAfterDelay
@@ -4887,11 +4894,13 @@
         (type Bitmap)
         (type Char)
         (type AlertDialog)
+        (type Builder)
         (type AdapterView)
         (type AutoCompleteTextView)
         (type Button)
         (type CharSequence)
         (type Context)
+        (type DialogInterface)
         (type Editable)
         (type EditText)
         (type File)
@@ -4930,6 +4939,21 @@
           (kotlin-member-call setSoftInputMode))
         (extern (alertDialogIsShowing (dialog : AlertDialog)) : Bool
           (kotlin-member-get isShowing))
+        (extern (alertDialogBuilderSetPositiveButtonRaw
+                  (builder : Builder)
+                  (text : String)
+                  (listener : (-> DialogInterface Int32 Unit))) : Builder
+          (kotlin-member-call setPositiveButton))
+        (extern (alertDialogBuilderSetNegativeButtonRaw
+                  (builder : Builder)
+                  (text : String)
+                  (listener : (-> DialogInterface Int32 Unit))) : Builder
+          (kotlin-member-call setNegativeButton))
+        (extern (alertDialogBuilderSetNeutralButtonRaw
+                  (builder : Builder)
+                  (text : String)
+                  (listener : (-> DialogInterface Int32 Unit))) : Builder
+          (kotlin-member-call setNeutralButton))
         (extern (autoCompleteDropDownHeightSet
                   (view : AutoCompleteTextView)
                   (height : Int32)) : Unit
@@ -5277,6 +5301,15 @@
                   (rect : FloatArray)
                   (detectedIds : (List String))) : Unit
           (kotlin-member-call showApproveDialog))
+        (extern (mainActivityOpenAnyPdfRaw
+                  (activity : MainActivity)) : Unit
+          (kotlin-member-call openAnyPdf))
+        (extern (mainActivityChooseSsdPdfFolderRaw
+                  (activity : MainActivity)) : Unit
+          (kotlin-member-call chooseSsdPdfFolder))
+        (extern (mainActivityRequestDownloadAccessRaw
+                  (activity : MainActivity)) : Unit
+          (kotlin-member-call requestDownloadAccess))
         (extern (mainActivityReviewViewSet
                   (activity : MainActivity)
                   (view : SsdReviewView)) : Unit
@@ -6499,6 +6532,73 @@
             button
             (lambda ((unused : View))
               (invoke action))))
+        (def (alertDialogBuilderSetPositiveAction
+               (builder : Builder)
+               (text : String)
+               (action : (-> Unit))) : Builder
+          (alertDialogBuilderSetPositiveButtonRaw
+            builder
+            text
+            (lambda ((unusedDialog : DialogInterface) (unusedWhich : Int32))
+              (invoke action))))
+        (def (alertDialogBuilderSetNegativeAction
+               (builder : Builder)
+               (text : String)
+               (action : (-> Unit))) : Builder
+          (alertDialogBuilderSetNegativeButtonRaw
+            builder
+            text
+            (lambda ((unusedDialog : DialogInterface) (unusedWhich : Int32))
+              (invoke action))))
+        (def (alertDialogBuilderSetNeutralAction
+               (builder : Builder)
+               (text : String)
+               (action : (-> Unit))) : Builder
+          (alertDialogBuilderSetNeutralButtonRaw
+            builder
+            text
+            (lambda ((unusedDialog : DialogInterface) (unusedWhich : Int32))
+              (invoke action))))
+        (def (mainActivitySetPositiveChooseSsdPdfFolder
+               (builder : Builder)
+               (activity : MainActivity)) : Builder
+          (alertDialogBuilderSetPositiveAction
+            builder
+            "Choose Folder"
+            (lambda ()
+              (mainActivityChooseSsdPdfFolderRaw activity))))
+        (def (mainActivitySetNeutralChooseSsdPdfFolder
+               (builder : Builder)
+               (activity : MainActivity)) : Builder
+          (alertDialogBuilderSetNeutralAction
+            builder
+            "Choose Folder"
+            (lambda ()
+              (mainActivityChooseSsdPdfFolderRaw activity))))
+        (def (mainActivitySetPositiveOpenAnyPdf
+               (builder : Builder)
+               (activity : MainActivity)) : Builder
+          (alertDialogBuilderSetPositiveAction
+            builder
+            "Open Any"
+            (lambda ()
+              (mainActivityOpenAnyPdfRaw activity))))
+        (def (mainActivitySetNegativeOpenAnyPdf
+               (builder : Builder)
+               (activity : MainActivity)) : Builder
+          (alertDialogBuilderSetNegativeAction
+            builder
+            "Open Any"
+            (lambda ()
+              (mainActivityOpenAnyPdfRaw activity))))
+        (def (mainActivitySetPositiveRequestDownloadAccess
+               (builder : Builder)
+               (activity : MainActivity)) : Builder
+          (alertDialogBuilderSetPositiveAction
+            builder
+            "Access Downloads"
+            (lambda ()
+              (mainActivityRequestDownloadAccessRaw activity))))
         (def (permissionResultGranted (actual : Int32) (granted : Int32)) : Bool
           (= actual granted))
         (def (downloadAccessBeforeRuntimePermissions (beforeRuntimePermissions : Bool)) : Bool
@@ -8097,7 +8197,7 @@
        "        }"
        "    }"
        ""
-       "    private fun openAnyPdf() {"
+       "    internal fun openAnyPdf() {"
        "        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {"
        "            addCategory(Intent.CATEGORY_OPENABLE)"
        "            type = \"application/pdf\""
@@ -8108,7 +8208,7 @@
        "        startActivityForResult(intent, REQ_OPEN_PDF)"
        "    }"
        ""
-       "    private fun chooseSsdPdfFolder() {"
+       "    internal fun chooseSsdPdfFolder() {"
        "        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {"
        "            addFlags("
        "                Intent.FLAG_GRANT_READ_URI_PERMISSION or"
@@ -8121,7 +8221,7 @@
        "        startActivityForResult(intent, REQ_OPEN_SSD_PDF_TREE)"
        "    }"
        ""
-       "    private fun requestDownloadAccess() {"
+       "    internal fun requestDownloadAccess() {"
        "        mainActivitySetReopenSsdBrowserOnResume(this, true)"
        "        if (sdkAtLeast(Build.VERSION.SDK_INT, Build.VERSION_CODES.R)) {"
        "            val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {"
@@ -8852,12 +8952,13 @@
        "                val choices = findSsdPdfsFromTree(treeUri)"
        "                runOnUiThread {"
        "                    if (ssdPdfChoicesEmpty(choices)) {"
-       "                        AlertDialog.Builder(this)"
-       "                            .setTitle(noSsdPdfsTitle())"
-       "                            .setMessage(noSsdPdfsInFolderMessage())"
-       "                            .setNegativeButton(\"Cancel\", null)"
-       "                            .setPositiveButton(\"Choose Folder\") { _, _ -> chooseSsdPdfFolder() }"
-       "                            .show()"
+       "                        mainActivitySetPositiveChooseSsdPdfFolder("
+       "                            AlertDialog.Builder(this)"
+       "                                .setTitle(noSsdPdfsTitle())"
+       "                                .setMessage(noSsdPdfsInFolderMessage())"
+       "                                .setNegativeButton(\"Cancel\", null),"
+       "                            this"
+       "                        ).show()"
        "                        setStatus(noSsdPdfsChooseFolderStatus())"
        "                        return@runOnUiThread"
        "                    }"
@@ -8874,27 +8975,35 @@
        "    }"
        ""
        "    private fun showPdfChoiceDialog(choices: List<SsdPdfChoice>, title: String) {"
-       "        AlertDialog.Builder(this)"
-       "            .setTitle(title)"
-       "            .setItems(ssdPdfChoiceLabels(choices).toTypedArray()) { _, which ->"
-       "                loadPdf(ssdPdfChoiceUriAt(choices, which), Intent.FLAG_GRANT_READ_URI_PERMISSION)"
-       "            }"
-       "            .setNegativeButton(\"Cancel\", null)"
-       "            .setNeutralButton(\"Change Folder\") { _, _ -> chooseSsdPdfFolder() }"
-       "            .setPositiveButton(\"Open Any\") { _, _ -> openAnyPdf() }"
-       "            .show()"
+       "        mainActivitySetPositiveOpenAnyPdf("
+       "            mainActivitySetNeutralChooseSsdPdfFolder("
+       "                AlertDialog.Builder(this)"
+       "                    .setTitle(title)"
+       "                    .setItems(ssdPdfChoiceLabels(choices).toTypedArray()) { _, which ->"
+       "                        loadPdf(ssdPdfChoiceUriAt(choices, which), Intent.FLAG_GRANT_READ_URI_PERMISSION)"
+       "                    }"
+       "                    .setNegativeButton(\"Cancel\", null),"
+       "                this"
+       "            ),"
+       "            this"
+       "        ).show()"
        "        setStatus(ssdPdfFoundStatus(choices))"
        "    }"
        ""
        "    private fun showNoSsdPdfsDialog() {"
        "        val message = noSsdPdfsDialogMessage(hasDirectDownloadAccess())"
-       "        AlertDialog.Builder(this)"
-       "            .setTitle(noSsdPdfsTitle())"
-       "            .setMessage(message)"
-       "            .setNegativeButton(\"Open Any\") { _, _ -> openAnyPdf() }"
-       "            .setNeutralButton(\"Choose Folder\") { _, _ -> chooseSsdPdfFolder() }"
-       "            .setPositiveButton(\"Access Downloads\") { _, _ -> requestDownloadAccess() }"
-       "            .show()"
+       "        mainActivitySetPositiveRequestDownloadAccess("
+       "            mainActivitySetNeutralChooseSsdPdfFolder("
+       "                mainActivitySetNegativeOpenAnyPdf("
+       "                    AlertDialog.Builder(this)"
+       "                        .setTitle(noSsdPdfsTitle())"
+       "                        .setMessage(message),"
+       "                    this"
+       "                ),"
+       "                this"
+       "            ),"
+       "            this"
+       "        ).show()"
        "        setStatus(noSsdPdfsFoundStatus())"
        "    }"
        ""