chromium/chrome/browser/ash/system_web_apps/system_web_app_background_task.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_ASH_SYSTEM_WEB_APPS_SYSTEM_WEB_APP_BACKGROUND_TASK_H_
#define CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_SYSTEM_WEB_APP_BACKGROUND_TASK_H_

#include <memory.h>

#include <optional>
#include <utility>

#include "ash/webui/system_apps/public/system_web_app_type.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/one_shot_event.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/ash/system_web_apps/types/system_web_app_background_task_info.h"
#include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/webapps/browser/web_contents/web_app_url_loader.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"

class Profile;

namespace ash {

// Used to manage a running periodic background task for a SWA.
class SystemWebAppBackgroundTask {
 public:
  enum TimerState {
    INITIAL_WAIT = 0,
    WAIT_PERIOD = 1,
    WAIT_IDLE = 2,
    INACTIVE = 3
  };

  // Wait for 2 minutes before starting background tasks. User login is busy,
  // and this will give a little time to settle down. We could get even more
  // sophisticated, and smear all the different start_immediately tasks across a
  // couple minutes instead of setting their start timers to the same time.
  static const int kInitialWaitForBackgroundTasksSeconds = 120;

  // User idle for 1 minute.
  static const int kIdleThresholdSeconds = 60;

  // Else, poll every 30 seconds
  static const int kIdlePollIntervalSeconds = 30;

  // For up to an hour.
  static const int kIdlePollMaxTimeToWaitSeconds = 3600;

  SystemWebAppBackgroundTask(Profile* profile,
                             const SystemWebAppBackgroundTaskInfo& info);
  ~SystemWebAppBackgroundTask();

  // Start the timer, at the specified period. This will also run immediately if
  // needed
  void StartTask();

  // Bring down the background task if open, and stop the timer.
  void StopTask();

  bool open_immediately_for_testing() const { return open_immediately_; }

  SystemWebAppType app_type_for_testing() const { return app_type_; }

  GURL url_for_testing() const { return url_; }

  content::WebContents* web_contents_for_testing() const {
    return web_contents_.get();
  }

  std::optional<base::TimeDelta> period_for_testing() const { return period_; }

  unsigned long opened_count_for_testing() const { return opened_count_; }

  unsigned long timer_activated_count_for_testing() const {
    return timer_activated_count_;
  }

  base::Time polling_since_time_for_testing() const {
    return polling_since_time_;
  }

  webapps::WebAppUrlLoader* UrlLoaderForTesting() {
    return web_app_url_loader_.get();
  }

  // Set the url loader for testing. Takes ownership of the argument.
  void SetUrlLoaderForTesting(
      std::unique_ptr<webapps::WebAppUrlLoader> loader) {
    web_app_url_loader_ = std::move(loader);
  }

  TimerState get_state_for_testing() const { return state_; }

  base::OneShotTimer* get_timer_for_testing() { return timer_.get(); }

 private:
  // A delegate to reset the WebContents owned by this background task and free
  // up the resources. Called when the page calls window.close() to exit.
  class CloseDelegate : public content::WebContentsDelegate {
   public:
    explicit CloseDelegate(SystemWebAppBackgroundTask* task) : task_(task) {}
    void CloseContents(content::WebContents* contents) override;

   private:
    raw_ptr<SystemWebAppBackgroundTask> task_;
  };
  // A state machine to either poll and fail, stop polling and succeed, or stop
  // polling and fail
  void MaybeOpenPage();

  void NavigateBackgroundPage();
  void OnPageReady(webapps::WebAppUrlLoaderResult);

  void CloseWebContents(content::WebContents* contents);

  raw_ptr<Profile> profile_;
  SystemWebAppType app_type_;
  std::unique_ptr<content::WebContents> web_contents_;
  std::unique_ptr<webapps::WebAppUrlLoader> web_app_url_loader_;
  std::unique_ptr<base::OneShotTimer> timer_;
  TimerState state_;
  GURL url_;
  std::optional<base::TimeDelta> period_;
  unsigned long opened_count_ = 0U;
  unsigned long timer_activated_count_ = 0U;
  bool open_immediately_ = false;
  base::Time polling_since_time_;
  CloseDelegate delegate_;

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

}  // namespace ash

#endif  // CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_SYSTEM_WEB_APP_BACKGROUND_TASK_H_