Public Access
Merge branch 'claude/vault-creation-sharing-62c0b6'
# Conflicts: # README.md
This commit is contained in:
@@ -1327,3 +1327,122 @@ rather than two. There is no confirmation prompt, deliberately.
|
||||
|
||||
**Failure means:** a phone that still unlocks itself after this is the local half not happening, which is the
|
||||
half that matters when the handset is the thing that was lost.
|
||||
|
||||
---
|
||||
|
||||
## Phase 14 — Moving files to and from the phone's remote
|
||||
|
||||
Every check here needs a real Android device or emulator, a host with SFTP or a bucket, and at least one
|
||||
document on the phone to send. What is automated is what can be: `TransferQueueingTests` says a staged
|
||||
upload obeys the same rules as any other and that a delivered download refuses a directory before the
|
||||
picker's damage is done. What cannot be automated is everything below — the two system pickers are another
|
||||
application, and the staging copies, the delivery, the notification and the resume are all things only a
|
||||
running phone does.
|
||||
|
||||
### 14.1 ADD FILES opens the system picker, and takes more than one
|
||||
|
||||
Connect to a host on SFTP, navigate somewhere writable, press **ADD FILES**, and choose two documents in one
|
||||
go — long-press to multi-select in Android's picker.
|
||||
|
||||
**Pass:** two rows appear in the queue with the names the picker showed, and both land in the directory the
|
||||
breadcrumb names. The pane's listing shows them after **↻**.
|
||||
|
||||
**Failure means:** one row from a two-document pick is `PickAsync` losing the rest, and two rows with one
|
||||
name is the per-file staging directory having gone — that is the overwrite `DocumentStaging` documents, and
|
||||
it silently uploads the same bytes twice.
|
||||
|
||||
### 14.2 The name that arrives is the name that was picked · **the one most likely to be wrong**
|
||||
|
||||
Pick a document whose display name has a space and a non-Latin character in it, and one from a cloud
|
||||
provider — Drive, or the Downloads shortcut — rather than local storage.
|
||||
|
||||
**Pass:** the file on the host is called what the picker called it. A cloud document uploads too, or fails
|
||||
with the provider's own message in the status line rather than a crash.
|
||||
|
||||
**Failure means:** a mangled name is `SafeName` over-reaching. A name that reaches the host with a `/` in it
|
||||
is `SafeName` under-reaching, and that one writes to a path nobody chose. A cloud document that hangs is
|
||||
the copy being made on the interface thread — the whole reason `CopyInAsync` leaves it.
|
||||
|
||||
### 14.3 The queue is bounded, and the buttons stay reachable
|
||||
|
||||
Queue five or six files at once, on a small phone if there is one.
|
||||
|
||||
**Pass:** the queue scrolls inside its own region and **ADD FILES**, **DELETE** and **CLOSE** are all still
|
||||
on screen. Every button is a thumb's size.
|
||||
|
||||
**Failure means:** buttons pushed off the bottom is the `MaxHeight` gone from the queue's scroller, and it
|
||||
makes the screen unusable exactly when somebody has queued the most work.
|
||||
|
||||
### 14.4 A stopped upload resumes rather than starting again
|
||||
|
||||
Start a large upload, press **STOP** part way, then press **RESUME**.
|
||||
|
||||
**Pass:** it carries on from roughly where it stopped rather than from zero — the progress text is the thing
|
||||
to read.
|
||||
|
||||
**Failure means:** restarting from zero means the staged copy was deleted at the stop, which is precisely
|
||||
what `QueueStagedUploads` does not do and why it does not. A failure saying the file cannot be found is the
|
||||
same bug, one step further along.
|
||||
|
||||
### 14.5 The copies do not accumulate · **the one nothing else would catch**
|
||||
|
||||
Note the app's storage in Android Settings → Apps → DodoSSH → Storage. Upload a large file, let it finish,
|
||||
and look again. Then stop an upload part way, leave it stopped, force-stop the app and relaunch it.
|
||||
|
||||
**Pass:** storage returns to about what it was after the successful upload — the copy is deleted the moment
|
||||
the transfer completes. After the stopped one, the cache is bigger while the app stays open (the copy is
|
||||
being kept for RESUME) and back to its old size after the relaunch, which is `DocumentStaging.Sweep`.
|
||||
|
||||
**Failure means:** growth after a successful upload is `ReleaseStaged` not firing, and every file sent
|
||||
leaves a second copy on the phone until Android reclaims the cache. Growth that survives a relaunch is the
|
||||
sweep not running.
|
||||
|
||||
### 14.6 The notification is up while it transfers, and gone afterwards
|
||||
|
||||
Queue several files in each direction, put the phone to sleep with the screen off, and wait.
|
||||
|
||||
**Pass:** the foreground notification is up, the transfers finish while the screen is off, and the
|
||||
notification goes away when the last one does — with no shell open. With a shell open it stays, because that
|
||||
is what it was already for.
|
||||
|
||||
**Failure means:** an upload that stalls with the screen off is the count not reaching
|
||||
`SessionForegroundService`, and Android has stopped the process mid-transfer. A notification left up
|
||||
afterwards is `ActivityChanged` not being subscribed — the other end of the same wire.
|
||||
|
||||
### 14.7 SAVE FILE writes where you pointed it, and the file opens
|
||||
|
||||
Select a file on the host — something with a viewer, an image or a PDF — press **SAVE FILE**, and put it
|
||||
somewhere reachable: Downloads, or a folder in Drive. When the transfer finishes, open it from the phone's
|
||||
own Files app.
|
||||
|
||||
**Pass:** the status line says it was saved, the file is where the picker was pointed under the name shown
|
||||
there, and it opens with the right contents. The queue row says DONE.
|
||||
|
||||
**Failure means:** a row that says DONE with nothing at the destination is `DeliverAsync` never running —
|
||||
the delivery is registered per transfer id, and losing it makes the download look like a success while the
|
||||
bytes sit in a cache nobody can reach. A file that is there but empty or truncated is the copy out, not the
|
||||
transfer: check the `SetLength(0)` and that the write stream is being disposed before the status is written.
|
||||
|
||||
### 14.8 The button is dead until a file is chosen, and refuses a directory
|
||||
|
||||
With nothing selected, look at **SAVE FILE**. Then select a directory row.
|
||||
|
||||
**Pass:** disabled in both cases — it needs a connected remote and a selected *file*, which is the desktop's
|
||||
own `CanDownload`.
|
||||
|
||||
**Failure means:** an enabled button over a directory reaches `QueueDeliveredDownload`'s refusal, which is
|
||||
the right answer arriving too late: the save picker has already created an empty file, so the person is left
|
||||
with a file they did not want and a message saying nothing happened.
|
||||
|
||||
### 14.9 A download that fails leaves the empty file it warned about
|
||||
|
||||
Point SAVE FILE at a destination for a large file, then break the transfer — turn off Wi-Fi and mobile data
|
||||
while it runs.
|
||||
|
||||
**Pass:** the row goes to FAILED with the reason, the status line does not claim it was saved, and there is
|
||||
an empty file at the destination. Reconnect, press **RETRY**, and the same destination fills in — the
|
||||
delivery survives the failure because it is held against the transfer rather than the attempt.
|
||||
|
||||
**Failure means:** a retry that succeeds but leaves the destination empty is the delivery having been
|
||||
dropped on the failure. An error saying the staged file is missing is the copy having been deleted at the
|
||||
stop, which is what `QueueDeliveredDownload` documents it does not do.
|
||||
|
||||
Reference in New Issue
Block a user