chromium/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h

// Copyright 2021 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_APPS_APP_SERVICE_PUBLISHERS_WEB_APPS_CROSAPI_H_
#define CHROME_BROWSER_APPS_APP_SERVICE_PUBLISHERS_WEB_APPS_CROSAPI_H_

#include <optional>
#include <string>
#include <vector>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/apps/almanac_api_client/device_info_manager.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
#include "chrome/browser/apps/app_service/app_service_proxy_forward.h"
#include "chrome/browser/apps/app_service/launch_result_type.h"
#include "chrome/browser/apps/app_service/publishers/app_publisher.h"
#include "chromeos/crosapi/mojom/app_service.mojom.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/capability_access.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "components/services/app_service/public/cpp/menu.h"
#include "components/services/app_service/public/cpp/permission.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace apps {
struct MenuItems;
}

namespace base {
class Location;
}  // namespace base

namespace apps {

class StandaloneBrowserPublisherTest;

struct AppLaunchParams;

// An app publisher for crosapi web apps. This is a proxy publisher that lives
// in ash-chrome, and the apps will be published over crosapi. This proxy
// publisher will also handle reconnection when the crosapi connection drops.
//
// See components/services/app_service/README.md.
class WebAppsCrosapi : public KeyedService,
                       public apps::AppPublisher,
                       public crosapi::mojom::AppPublisher {
 public:
  explicit WebAppsCrosapi(AppServiceProxy* proxy);
  ~WebAppsCrosapi() override;

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

  // Register the web apps host from lacros-chrome to allow lacros-chrome
  // publishing web apps to app service in ash-chrome.
  void RegisterWebAppsCrosapiHost(
      mojo::PendingReceiver<crosapi::mojom::AppPublisher> receiver);

 private:
  friend class StandaloneBrowserPublisherTest;
  FRIEND_TEST_ALL_PREFIXES(StandaloneBrowserPublisherTest,
                           WebAppsCrosapiNotUpdated);
  FRIEND_TEST_ALL_PREFIXES(StandaloneBrowserPublisherTest,
                           WebAppsCrosapiUpdated);
  FRIEND_TEST_ALL_PREFIXES(StandaloneBrowserPublisherTest,
                           WebAppsCrosapiUpdatedCapability);
  FRIEND_TEST_ALL_PREFIXES(StandaloneBrowserPublisherTest,
                           WebAppsNotInitializedIfRegisterFirst);
  FRIEND_TEST_ALL_PREFIXES(StandaloneBrowserPublisherTest,
                           WebAppsInitializedForEmptyList);
  FRIEND_TEST_ALL_PREFIXES(StandaloneBrowserPublisherTest,
                           WebAppsCrosapiCapabilityReset);

  // apps::AppPublisher overrides.
  void GetCompressedIconData(const std::string& app_id,
                             int32_t size_in_dip,
                             ui::ResourceScaleFactor scale_factor,
                             LoadIconCallback callback) override;
  void Launch(const std::string& app_id,
              int32_t event_flags,
              LaunchSource launch_source,
              WindowInfoPtr window_info) override;
  void LaunchAppWithFiles(const std::string& app_id,
                          int32_t event_flags,
                          LaunchSource launch_source,
                          std::vector<base::FilePath> file_paths) override;
  void LaunchAppWithIntent(const std::string& app_id,
                           int32_t event_flags,
                           IntentPtr intent,
                           LaunchSource launch_source,
                           WindowInfoPtr window_info,
                           LaunchCallback callback) override;
  void LaunchAppWithParams(AppLaunchParams&& params,
                           LaunchCallback callback) override;
  void LaunchShortcut(const std::string& app_id,
                      const std::string& shortcut_id,
                      int64_t display_id) override;
  void SetPermission(const std::string& app_id,
                     PermissionPtr permission) override;
  void Uninstall(const std::string& app_id,
                 UninstallSource uninstall_source,
                 bool clear_site_data,
                 bool report_abuse) override;
  void GetMenuModel(const std::string& app_id,
                    MenuType menu_type,
                    int64_t display_id,
                    base::OnceCallback<void(MenuItems)> callback) override;
  void UpdateAppSize(const std::string& app_id) override;
  void SetWindowMode(const std::string& app_id,
                     WindowMode window_mode) override;
  void PauseApp(const std::string& app_id) override;
  void UnpauseApp(const std::string& app_id) override;
  void StopApp(const std::string& app_id) override;
  void OpenNativeSettings(const std::string& app_id) override;
  void ExecuteContextMenuCommand(const std::string& app_id,
                                 int command_id,
                                 const std::string& shortcut_id,
                                 int64_t display_id) override;

  // crosapi::mojom::AppPublisher overrides.
  void OnApps(std::vector<AppPtr> deltas) override;
  void RegisterAppController(
      mojo::PendingRemote<crosapi::mojom::AppController> controller) override;
  void OnCapabilityAccesses(std::vector<CapabilityAccessPtr> deltas) override;

  bool LogIfNotConnected(const base::Location& from_here);

  void OnCrosapiDisconnected();
  void OnControllerDisconnected();

  void OnGetMenuModelFromCrosapi(
      const std::string& app_id,
      MenuType menu_type,
      MenuItems menu_items,
      base::OnceCallback<void(MenuItems)> callback,
      crosapi::mojom::MenuItemsPtr crosapi_menu_items);

  void PublishImpl(std::vector<AppPtr> deltas);
  void PublishCapabilityAccessesImpl(std::vector<CapabilityAccessPtr> deltas);
  void LaunchMallWithContext(int32_t event_flags,
                             apps::LaunchSource launch_source,
                             apps::WindowInfoPtr window_info,
                             apps::DeviceInfo device_info);

  // Stores a copy of the app deltas, which haven't been published to
  // AppRegistryCache yet. When the crosapi is bound or changed from disconnect
  // to bound, we need to publish all app deltas in this cache to
  // AppRegistryCache.
  std::vector<AppPtr> delta_app_cache_;

  // Stores a copy of the capability access deltas, which haven't been published
  // to AppRegistryCache yet. When the crosapi is bound or changed from
  // disconnect to bound, we need to publish all capability access deltas in
  // this cache to AppRegistryCache.
  std::vector<CapabilityAccessPtr> delta_capability_access_cache_;

  // Record if OnApps interface been called from the Lacros. If it is called
  // before Lacros web app controller registration, we should publish the
  // |delta_app_cache_| to initialize the web app AppType even it is empty.
  bool on_initial_apps_received_ = false;

  mojo::Receiver<crosapi::mojom::AppPublisher> receiver_{this};
  mojo::Remote<crosapi::mojom::AppController> controller_;
  const raw_ptr<AppServiceProxy> proxy_;
  bool should_notify_initialized_ = true;

  DeviceInfoManager device_info_manager_;

  base::WeakPtrFactory<WebAppsCrosapi> weak_factory_{this};
};

}  // namespace apps

#endif  // CHROME_BROWSER_APPS_APP_SERVICE_PUBLISHERS_WEB_APPS_CROSAPI_H_