chromium/chrome/browser/ash/video_conference/video_conference_app_service_client.h

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

#ifndef CHROME_BROWSER_ASH_VIDEO_CONFERENCE_VIDEO_CONFERENCE_APP_SERVICE_CLIENT_H_
#define CHROME_BROWSER_ASH_VIDEO_CONFERENCE_VIDEO_CONFERENCE_APP_SERVICE_CLIENT_H_

#include <map>
#include <string>

#include "ash/public/cpp/session/session_controller.h"
#include "ash/public/cpp/session/session_observer.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h"
#include "chromeos/crosapi/mojom/video_conference.mojom.h"
#include "components/services/app_service/public/cpp/app_capability_access_cache.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/instance_registry.h"

namespace apps {
class AppRegistryCache;
class InstanceRegistry;
}  // namespace apps

namespace ukm {
class UkmRecorder;
}

namespace video_conference {
class VideoConferenceUkmHelper;
}

namespace ash {

// VideoConferenceAppServiceClient is a client class for CrOS
// videoconferencing. It detects the launching/closing/media-capturing actions
// from apps through AppService and notifies VideoConferenceManagerAsh.
class VideoConferenceAppServiceClient
    : public crosapi::mojom::VideoConferenceManagerClient,
      public apps::AppCapabilityAccessCache::Observer,
      public apps::InstanceRegistry::Observer,
      public SessionObserver {
 public:
  using AppIdString = std::string;
  using VideoConferencePermissions =
      video_conference::VideoConferencePermissions;

  // AppState records information that is required for VideoConferenceManagerAsh
  // to show correct icons.
  struct AppState {
    // Used for uniquely identifying an App in VideoConferenceManagerAsh.
    base::UnguessableToken token;
    base::Time last_activity_time;
    bool is_capturing_microphone = false;
    bool is_capturing_camera = false;
  };

  VideoConferenceAppServiceClient();

  VideoConferenceAppServiceClient(const VideoConferenceAppServiceClient&) =
      delete;
  VideoConferenceAppServiceClient& operator=(
      const VideoConferenceAppServiceClient&) = delete;

  ~VideoConferenceAppServiceClient() override;

  // crosapi::mojom::VideoConferenceManagerClient overrides.
  void GetMediaApps(GetMediaAppsCallback callback) override;
  void ReturnToApp(const base::UnguessableToken& token,
                   ReturnToAppCallback callback) override;
  void SetSystemMediaDeviceStatus(
      crosapi::mojom::VideoConferenceMediaDevice device,
      bool disabled,
      SetSystemMediaDeviceStatusCallback callback) override;
  void StopAllScreenShare() override;

  // apps::AppCapabilityAccessCache::Observer overrides.
  void OnCapabilityAccessUpdate(
      const apps::CapabilityAccessUpdate& update) override;
  void OnAppCapabilityAccessCacheWillBeDestroyed(
      apps::AppCapabilityAccessCache* cache) override;

  // apps::InstanceRegistry::Observer overrides.
  void OnInstanceUpdate(const apps::InstanceUpdate& update) override;
  void OnInstanceRegistryWillBeDestroyed(
      apps::InstanceRegistry* cache) override;

  // SessionObserver overrides.
  void OnSessionStateChanged(session_manager::SessionState state) override;

 private:
  friend class VideoConferenceAppServiceClientTest;

  // Returns current VideoConferenceAppServiceClient for testing purpose.
  static VideoConferenceAppServiceClient* GetForTesting();

  // Returns the name of the app with `app_id`.
  std::string GetAppName(const AppIdString& app_id);

  // Returns the current camera/microphone permission status for `app_id`.
  VideoConferencePermissions GetAppPermission(const AppIdString& app_id);

  // Returns the AppType of `app_id`.
  apps::AppType GetAppType(const AppIdString& app_id);

  // Returns AppState of `app_id`; adds if doesn't exist yet.
  AppState& GetOrAddAppState(const AppIdString& app_id);

  // Removes `app_id` from `id_to_app_state_` if there is no running instance
  // for it.
  void MaybeRemoveApp(const AppIdString& app_id);

  // Calculates a new `crosapi::mojom::VideoConferenceMediaUsageStatus` from all
  // current VC apps and notifies the manager if a field has changed.
  void HandleMediaUsageUpdate();

  // These registries are used for observing app behaviors.
  raw_ptr<apps::InstanceRegistry> instance_registry_;
  raw_ptr<apps::AppRegistryCache> app_registry_;
  raw_ptr<apps::AppCapabilityAccessCache> capability_cache_;

  // Unique id associated with this client. It is used by the VcManager to
  // identify clients.
  const base::UnguessableToken client_id_;

  // Only used for testing purpose.
  raw_ptr<ukm::UkmRecorder> test_ukm_recorder_ = nullptr;

  // Current status_ aggregated from all apps in `id_to_app_state_`.
  crosapi::mojom::VideoConferenceMediaUsageStatusPtr status_;

  // The following two fields are true if the camera/microphone is system-wide
  // software disabled OR disabled via a hardware switch.
  bool camera_system_disabled_{false};
  bool microphone_system_disabled_{false};

  // This records a list of AppState; each represents a video conference app.
  std::map<AppIdString, AppState> id_to_app_state_;

  std::map<AppIdString,
           std::unique_ptr<video_conference::VideoConferenceUkmHelper>>
      id_to_ukm_hepler_;

  base::ScopedObservation<SessionController, SessionObserver>
      session_observation_{this};

  base::ScopedObservation<apps::InstanceRegistry,
                          apps::InstanceRegistry::Observer>
      instance_registry_observation_{this};

  base::ScopedObservation<apps::AppCapabilityAccessCache,
                          apps::AppCapabilityAccessCache::Observer>
      app_capability_observation_{this};

  base::WeakPtrFactory<VideoConferenceAppServiceClient> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // CHROME_BROWSER_ASH_VIDEO_CONFERENCE_VIDEO_CONFERENCE_APP_SERVICE_CLIENT_H_