chromium/chrome/browser/ui/webui/nearby_share/nearby_share.mojom

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

module nearby_share.mojom;

import "chrome/browser/ui/webui/nearby_share/nearby_share_share_type.mojom";
import "chromeos/ash/services/nearby/public/mojom/nearby_share_target_types.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
import "url/mojom/url.mojom";

// Contains the minimum amount of information needed to show the user a preview
// of their share when they are confirming a send or receive with a share
// target.
struct PayloadPreview {
  // A description that is different for each sharing case:
  // 1) For a text share this is a limited/redacted preview of the full text.
  // 2) For a single file share this is the file name.
  // 3) For a multiple file share this contains the first file name. This will
  //    be used in a translation template like this 'file.ext and N other files'
  string description;
  // 0 for a direct text share, or the number of files being shared.
  int32 file_count;
  // The type of share so the UI knows how to preview it.
  ShareType share_type;
};

// Describes a nearby device that is able to receive data via Nearby Share.
struct ShareTarget {
  // Unique identifier during the current discovery session. The same physical
  // device might have a different value each time StartDiscovery() is called.
  mojo_base.mojom.UnguessableToken id;
  // User defined name of this share target.
  string name;
  // Device type of this share target.
  ShareTargetType type;
  // URL of the share target image.
  url.mojom.Url? image_url;
  // Payload preview for the attachment(s).
  PayloadPreview payload_preview;
  // True if the remote device is signed into the same Gaia account as the user.
  bool for_self_share;
};

// Result of selecting a share target.
enum SelectShareTargetResult {
  // Successfully selected share target. Transfer will continue from here.
  kOk,
  // Unknown error while selecting the share target.
  kError,
  // Could not find the selected share target. It may have been lost in the
  // mean time.
  kInvalidShareTarget,
};

// Interface to be notified about nearby devices. The same ShareTarget might be
// discovered multiple times but will have the same id during one session. This
// is implemented in UI surfaces and called from the browser process.
interface ShareTargetListener {
  // Reports a nearby device found via Nearby Share.
  OnShareTargetDiscovered(ShareTarget share_target);

  // Reports that a previously discovered device is no longer available.
  OnShareTargetLost(ShareTarget share_target);
};

// Status of the current transfer. This mirrors the Status enum at
// chrome/browser/nearby_sharing/transfer_metadata.h, but drops the unused
// statuses kMediaDownloading and kExternalProviderLaunched.
enum TransferStatus {
  kUnknown,
  // A remote device is connecting.
  kConnecting,
  // The user of the local device needs to accept or reject the transfer. This
  // involves showing a token on both devices to be compared by the user.
  kAwaitingLocalConfirmation,
  // The remote device needs to accept the transfer. We still need to show the
  // token on this device so the other user can compare it.
  kAwaitingRemoteAcceptance,
  // The connection was lost before the remote accepted/rejected.
  kAwaitingRemoteAcceptanceFailed,
  // The current transfer is now in progress after both users accepted the
  // transfer on their devices.
  kInProgress,
  // The current transfer is complete and successful.
  kComplete,
  // The current transfer failed.
  kFailed,
  // The remote device rejected the transfer.
  kRejected,
  // The remote device cancelled the transfer.
  kCancelled,
  // The connection to a remote device timed out.
  kTimedOut,
  // The attachment could not be found, or the payload could not be created.
  kMediaUnavailable,
  // Not enough disk space to store the payload.
  kNotEnoughSpace,
  // The file type is not supported for sharing.
  kUnsupportedAttachmentType,
  // The advertisement failed to decode.
  kDecodeAdvertisementFailed,
  // The share target doesn't have a transfer update callback.
  kMissingTransferUpdateCallback,
  // Could not find the appropriate share target.
  kMissingShareTarget,
  // Could not find the appropriate endpoint id.
  kMissingEndpointId,
  // The transfer doesn't have any payloads.
  kMissingPayloads,
  // The Paired Key Verification step failed.
  kPairedKeyVerificationFailed,
  // The introduction frame is invalid.
  kInvalidIntroductionFrame,
  // The completed transfer didn't complete all expected payloads.
  kIncompletePayloads,
  // Could not create a share target for transfer.
  kFailedToCreateShareTarget,
  // The outgoing connection failed to initiate.
  kFailedToInitiateOutgoingConnection,
  // The outgoing connection response couldn't be read.
  kFailedToReadOutgoingConnectionResponse,
  // The connection unexpectedly disconnected.
  kUnexpectedDisconnection,
};

// Metadata associated with the current transfer.
struct TransferMetadata {
  // Status of the current transfer.
  TransferStatus status;
  // Represents transfer progress as a percentage.
  float progress;
  // Represents the UKey2 token from Nearby Connections. Null if no
  // UKey2 comparison is needed for this transfer.
  string? token;
  // Indicates whether this metadata has been seen before.
  bool is_original;
  // Indicates whether this is the last status for this transfer.
  bool is_final_status;
};

// Interface to be notified about transfer updates. Includes an optional token
// that needs to be shown to the user to confirm with the remote device. The
// token verification can be skipped for trusted devices in the contacts list
// but must be shown when sending to unknown devices. This interface is
// implemented in UI surfaces and called from the browser process.
interface TransferUpdateListener {
  // Called when the status of the current transfer changes.
  OnTransferUpdate(TransferStatus status, string? token);
};

// This enum contains the results from attempting to to start nearby discovery.
enum StartDiscoveryResult {
  // Nearby was able to start its discovery process sucessfully.
  kSuccess,
  // Nearby cannot start discovery because there is an existing file transfer
  // in progress.
  kErrorInProgressTransferring,
  // No supported discovery medium (i.e. Bluetooth, Wi-Fi, etc) is available.
  // This usually means the user does not have Bluetooth enabled/powered.
  kNoConnectionMedium,
  // Generic error for failing to start the nearby discovery process.
  kErrorGeneric,
};

// This enum represents the different possible results when registering a
// Receive Surface.
enum RegisterReceiveSurfaceResult {
  // Succeeded.
  kSuccess,
  // Failed.
  kFailure,
  // No supported discovery medium (i.e. Bluetooth, Wi-Fi, etc) is available.
  // This usually means the user does not have Bluetooth enabled/powered.
  kNoConnectionMedium,
  // There is already a transfer in progress.
  kTransferInProgress,
};

// Observer interface to receive updates when the Nearby utility process stops.
// Implemented on the browser process and used by UI surfaces.
interface DiscoveryObserver {
  // Called when the Nearby utility process stops.
  OnNearbyProcessStopped();

  // Called when discovery has started.
  OnStartDiscoveryResult(bool success);
};

// Manager interface for nearby device discovery. Implemented on the browser
// process and used by UI surfaces. The discovery manager is also responsible
// for previewing the current share with GetPayloadPreview() so the user can
// verify the attachments being sent before calling SelectShareTarget().
interface DiscoveryManager {
  // Allows the caller to observe DiscoveryManager events.
  AddDiscoveryObserver(pending_remote<DiscoveryObserver> observer);

  // Starts discovering nearby devices. The passed |listener| will be called
  // with any discovered devices. Returns before discovery has actually
  // started; see |DiscoveryObserver.OnStartDiscoveryResult()|.
  // Ensure StopDiscovery is called before invoking StartDiscovery again.
  StartDiscovery(pending_remote<ShareTargetListener> listener)
      => (StartDiscoveryResult result);

  // Stops the current discovery session. Call StartDiscovery to start
  // the session again.
  StopDiscovery() => ();

  // Select a previously discovered |share_target_id| to send data to. On
  // success this will return valid ConfirmationManager and
  // TransferUpdateListener interfaces to be used to show an additional
  // confirmation screen to accept or reject the transfer.
  SelectShareTarget(mojo_base.mojom.UnguessableToken share_target_id)
      => (SelectShareTargetResult result,
          pending_receiver<TransferUpdateListener>? transfer_update_listener,
          pending_remote<ConfirmationManager>? confirmation_manager);

  // Gets the PayloadPreview so the UI can show the user what they are about to
  // share.
  GetPayloadPreview() => (PayloadPreview payload_preview);
};

// Manager interface for the Nearby Share confirmation screen. Implemented on
// the browser process and used by UI surfaces.
interface ConfirmationManager {
  // Accepts a connection to the current Share Target.
  Accept() => (bool success);

  // Rejects a connection to the current Share Target.
  Reject() => (bool success);

  // Cancels a connection to the current Share Target.
  Cancel() => (bool success);
};

// Observer interface to receive updates when high visibility has changed
// and when an incoming share is requested and the user must confirm.
//
// This interface is implement in Javascript in the chrome://os-settings WebUI.
interface ReceiveObserver {
  // Called when high visibility receive state (foreground receive) has
  // changed and the new value is provided.
  OnHighVisibilityChanged(bool in_high_visibility);

  // Called when the status of the current transfer changes.
  OnTransferUpdate(ShareTarget share_target, TransferMetadata metadata);

  // Called when the Nearby utility process stops.
  OnNearbyProcessStopped();

  // Called when advertising fails to start. If advertising fails, then high
  // visibility will not be turned on.
  // |ReceiveManager.RegisterForegroundReceiveSurface()| may be called again
  // to reattempt.
  OnStartAdvertisingFailure();
};

// Allows the caller to observe changes to or query high visibility, or
// register/unregister a foreground receive surface, which will cause high
// visibility to start/stop respectively. Once in high visibility, the caller
// may observe incoming shares and accept or reject them.
//
// This interface runs in the browser process and is bound by os-settings which
// hosts the ui surface and implements the |ReceiveObserver|.
interface ReceiveManager {
  // Allows the caller to observe ReceiveManager events.
  AddReceiveObserver(pending_remote<ReceiveObserver> observer);

  // Determine if the user is currently in high visibility.
  IsInHighVisibility() => (bool in_high_visibility);

  // Attempt to register the receive manager as a foreground receive surface.
  // If |result| is kSuccess, then the surface has been registered; otherwise it
  // has not been registered. The foreground surface receives incoming
  // shares, and once one is registered, high visibility will become active
  // after a short while. Calling multiple times will have no additional effect.
  RegisterForegroundReceiveSurface() => (RegisterReceiveSurfaceResult result);

  // Attempt to unregister the receive manager as a foreground receive surface.
  // If |success| is true, then the surface is no longer registered; otherwise,
  // it is still registered. The foreground surface receives incoming shares,
  // and once it is no longer registered, high visibility will no longer be
  // active after a short while. Calling unregister before register will have
  // no effect.
  UnregisterForegroundReceiveSurface() => (bool success);

  // Accept the incoming share request by the share target id.
  Accept(mojo_base.mojom.UnguessableToken share_target_id) => (bool success);

  // Reject the incoming share request by the share target id.
  Reject(mojo_base.mojom.UnguessableToken share_target_id) => (bool success);

  // Records via Standard Feature Usage Logging whether or not
  // advertising successfully starts when the user clicks the
  // "Device nearby is sharing" notification.
  RecordFastInitiationNotificationUsage(bool success);
};