Public Access
Tell the keep-alive wire when the Files session opens and closes
HasLiveFileSession answers the phone's foreground-service question — is there a connection here that dying with the process would sever — and a bucket answers no, because HTTP holds nothing open. ActivityChanged now also fires at the end of MarkHostConnected and CloseSessionAsync, where both facts it reads are finally true together. Also makes the bucket pins test actually open a bucket: it never set Remote, so CONNECT dialled the auto-selected host, and its assertions passed only because that host had no pins either.
This commit is contained in:
@@ -620,6 +620,19 @@ internal sealed partial class TransfersViewModel : ObservableObject, IAsyncDispo
|
||||
[ObservableProperty]
|
||||
private string? connectedCipher;
|
||||
|
||||
/// <summary>
|
||||
/// Whether there is a live SFTP connection this session would lose by dying — the phone's foreground-
|
||||
/// service question, not the desktop's.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="ConnectedCipher"/> is already the fact that tells a host apart from a bucket, because only
|
||||
/// a host set it — a bucket is HTTP, per-request, and closes nothing a dying process would have kept
|
||||
/// open, so it answers false here even while <see cref="IsConnected"/> is true. Android reads this to
|
||||
/// decide whether an idle Files screen with no transfer moving still needs the process kept alive; the
|
||||
/// desktop has no such question because nothing stops its process for having gone quiet.
|
||||
/// </remarks>
|
||||
internal bool HasLiveFileSession => IsConnected && ConnectedCipher is not null;
|
||||
|
||||
/// <summary>The accepted host key's algorithm, e.g. <c>ssh-ed25519</c>. See <see cref="ConnectedCipher"/>.</summary>
|
||||
[ObservableProperty]
|
||||
private string? connectedHostKeyAlgorithm;
|
||||
@@ -745,13 +758,18 @@ internal sealed partial class TransfersViewModel : ObservableObject, IAsyncDispo
|
||||
|
||||
internal ObservableCollection<TransferRowViewModel> Transfers { get; } = [];
|
||||
|
||||
/// <summary>Raised on the UI thread whenever a transfer appears or changes state.</summary>
|
||||
/// <summary>
|
||||
/// Raised on the UI thread whenever a transfer appears or changes state, or a host or bucket connects or
|
||||
/// disconnects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For a head that has to tell the operating system what this process is doing — Android's foreground
|
||||
/// service, which must be up for as long as bytes are moving and down afterwards. An event rather than
|
||||
/// letting that head watch <see cref="Transfers"/> itself: the collection announces rows arriving and
|
||||
/// leaving, and the transition that matters most is neither of those but a row going from RUNNING to
|
||||
/// DONE without moving.
|
||||
/// service, which must be up for as long as bytes are moving, or a host session sits open, and down
|
||||
/// afterwards. An event rather than letting that head watch <see cref="Transfers"/> itself: the
|
||||
/// collection announces rows arriving and leaving, and the transition that matters most is neither of
|
||||
/// those but a row going from RUNNING to DONE without moving. Connecting and disconnecting are the other
|
||||
/// two transitions the service cares about — see <see cref="HasLiveFileSession"/> — and neither touches
|
||||
/// <see cref="Transfers"/> at all, so they need this same announcement made by hand.
|
||||
/// </remarks>
|
||||
internal event EventHandler? ActivityChanged;
|
||||
|
||||
@@ -1075,6 +1093,13 @@ internal sealed partial class TransfersViewModel : ObservableObject, IAsyncDispo
|
||||
// far as the remote's own auth.log is concerned, so a log of ours that omitted it would disagree with
|
||||
// the host's — and anybody comparing the two would be right to believe the host.
|
||||
connected = (ConnectedTo, row.Label, row.EntityId, TimeProvider.System.GetUtcNow());
|
||||
|
||||
// Raised here rather than from OnIsConnectedChanged, on purpose: IsConnected is set first, above,
|
||||
// and ConnectedCipher second — a partial method firing off the first assignment would read
|
||||
// HasLiveFileSession against a ConnectedCipher still holding whatever the previous session left
|
||||
// there. Only at the end of this method are both facts actually true together.
|
||||
OnPropertyChanged(nameof(HasLiveFileSession));
|
||||
ActivityChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1856,6 +1881,11 @@ internal sealed partial class TransfersViewModel : ObservableObject, IAsyncDispo
|
||||
RemoteTrail.Clear();
|
||||
SelectedRemoteEntry = null;
|
||||
|
||||
// Same ordering reason as the raise at the end of MarkHostConnected: both properties this reads are
|
||||
// already null above, so the raise belongs after them rather than in OnIsConnectedChanged. This also
|
||||
// covers OpenBucketAsync, which calls this method first and never itself turns HasLiveFileSession on.
|
||||
OnPropertyChanged(nameof(HasLiveFileSession));
|
||||
ActivityChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
|
||||
Reference in New Issue
Block a user