chromium/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.h

// Copyright 2019 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_UI_ASH_SHELF_APP_SERVICE_APP_SERVICE_APP_WINDOW_ARC_TRACKER_H_
#define CHROME_BROWSER_UI_ASH_SHELF_APP_SERVICE_APP_SERVICE_APP_WINDOW_ARC_TRACKER_H_

#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>

#include "ash/components/arc/arc_util.h"
#include "ash/public/cpp/shelf_types.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ash/app_list/arc/arc_app_list_prefs.h"
#include "chrome/browser/ash/arc/session/arc_session_manager_observer.h"

namespace arc {
class ArcAppShelfId;
}

namespace ash {
class ShelfItemDelegate;
}

namespace aura {
class window;
}

namespace gfx {
class ImageSkia;
}

class AppServiceAppWindowShelfController;
class AppServiceAppWindowShelfItemController;
class ArcAppWindowInfo;
class Profile;

// AppServiceAppWindowArcTracker observes the ArcAppListPrefs to handle ARC app
// window special cases, e.g. task id, closing ARC app windows, etc.
class AppServiceAppWindowArcTracker : public ArcAppListPrefs::Observer,
                                      public arc::ArcSessionManagerObserver {
 public:
  explicit AppServiceAppWindowArcTracker(
      AppServiceAppWindowShelfController* app_service_controller);
  ~AppServiceAppWindowArcTracker() override;

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

  void ActiveUserChanged(const std::string& user_email);

  // Invoked by controller to notify |window| visibility is changed.
  void HandleWindowVisibilityChanged(aura::Window* window);

  // Invoked by controller to notify |window| activated is changed.
  void HandleWindowActivatedChanged(aura::Window* window);

  // Invoked by controller to notify |window| is destroying.
  void HandleWindowDestroying(aura::Window* window);

  // Close all windows for 'app_id'.
  void CloseWindows(const std::string& app_id);

  // Invoked by controller to notify |window| may be replaced from ghost window
  // to app window.
  void OnWindowPropertyChanged(aura::Window* window,
                               const void* key,
                               intptr_t old);

  // ArcAppListPrefs::Observer:
  void OnAppStatesChanged(const std::string& app_id,
                          const ArcAppListPrefs::AppInfo& app_info) override;
  void OnAppRemoved(const std::string& app_id) override;
  void OnTaskCreated(int32_t task_id,
                     const std::string& package_name,
                     const std::string& activity,
                     const std::string& intent,
                     int32_t session_id) override;
  void OnTaskDescriptionChanged(int32_t task_id,
                                const std::string& label,
                                const arc::mojom::RawIconPngData& icon,
                                uint32_t primary_color,
                                uint32_t status_bar_color) override;
  void OnTaskDestroyed(int32_t task_id) override;
  void OnTaskSetActive(int32_t task_id) override;

  // Attaches controller and sets window's property when |window| is an ARC
  // window and has the related task id.
  void AttachControllerToWindow(aura::Window* window);

  // Adds the app window to |arc_window_candidates_|.
  void AddCandidateWindow(aura::Window* window);
  // Removes the app window from |arc_window_candidates_|.
  void RemoveCandidateWindow(aura::Window* window);

  // Removes controller from |app_shelf_group_to_controller_map_|.
  void OnItemDelegateDiscarded(const ash::ShelfID& shelf_id,
                               ash::ShelfItemDelegate* delegate);

  ash::ShelfID GetShelfId(aura::Window* window);

  int active_task_id() const { return active_task_id_; }

  int active_session_id() const { return active_session_id_; }

 private:
  using TaskIdToArcAppWindowInfo =
      std::map<int, std::unique_ptr<ArcAppWindowInfo>>;

  using SessionIdToArcAppWindowInfo =
      std::map<int, std::unique_ptr<ArcAppWindowInfo>>;

  // Maps shelf group id to controller. Shelf group id is optional parameter for
  // the Android task. If it is not set, app id is used instead.
  using ShelfGroupToAppControllerMap =
      std::map<arc::ArcAppShelfId, AppServiceAppWindowShelfItemController*>;

  // Checks |arc_window_candidates_| and attaches controller when they
  // are ARC app windows and have task id or session id.
  void CheckAndAttachControllers();
  void AttachControllerToTask(int taskId);
  void AttachControllerToSession(int session_id, const ArcAppWindowInfo& info);

  // arc::ArcSessionManagerObserver:
  void OnArcPlayStoreEnabledChanged(bool enabled) override;

  // Returns a task ID different from |task_id| that is part of the same
  // logical window. Return arc::kNoTaskId if there is no such window.
  // For consistency, always return the lowest such task ID.
  int GetTaskIdSharingLogicalWindow(int task_id);

  std::vector<int> GetTaskIdsForApp(const std::string& app_id) const;

  // Returns session ids of all ghost windows for the app of `arc_app_id`.
  std::vector<int> GetSessionIdsForApp(const std::string& app_id) const;

  // Invoked when the compressed data is converted to an ImageSkia.
  void OnIconLoaded(int32_t task_id,
                    const std::string& title,
                    const gfx::ImageSkia& icon);

  ArcAppWindowInfo* GetArcAppWindowInfo(aura::Window* window);

  // Invoked when the app is removed to close the ghost window with
  // `session_id`.
  void OnSessionDestroyed(int32_t session_id);

  const raw_ptr<Profile> observed_profile_;
  const raw_ptr<AppServiceAppWindowShelfController> app_service_controller_;

  TaskIdToArcAppWindowInfo task_id_to_arc_app_window_info_;
  SessionIdToArcAppWindowInfo session_id_to_arc_app_window_info_;
  ShelfGroupToAppControllerMap app_shelf_group_to_controller_map_;

  // Temporarily map session id to task id, starting from OnTaskCreated called
  // to exo application id set (until that `arc::GetWindowTaskId` can return
  // correct task id for window, or it will still be session id).
  std::map<int, int> session_id_to_task_id_map_;

  // ARC app task id could be created after the window initialized.
  // |arc_window_candidates_| is used to record those initialized ARC app
  // windows, which haven't been assigned a task id. When a task id is created,
  // the windows in |arc_window_candidates_| will be checked and attach the task
  // id. Once the window is assigned a task id, the window is removed from
  // |arc_window_candidates_|.
  std::set<raw_ptr<aura::Window, SetExperimental>> arc_window_candidates_;

  int active_task_id_ = arc::kNoTaskId;
  int active_session_id_ = arc::kNoTaskId;

  // TODO(crbug.com/40808991): A temp variable used to investigate whether
  // OnTaskDestroyed is called in the middle of OnTaskCreated. This can be
  // removed if we have the result.
  int task_id_being_created_ = arc::kNoTaskId;

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

#endif  // CHROME_BROWSER_UI_ASH_SHELF_APP_SERVICE_APP_SERVICE_APP_WINDOW_ARC_TRACKER_H_