chromium/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.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_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_SERVICE_WRAPPER_H_
#define CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_SERVICE_WRAPPER_H_

#include <string>
#include <vector>

#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chrome/browser/apps/app_service/app_service_proxy_forward.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/instance_registry.h"

class Profile;

namespace base {
class UnguessableToken;
}  // namespace base

namespace gfx {
class ImageSkia;
}  // namespace gfx

namespace ash {
namespace app_time {

class AppId;
struct PauseAppInfo;

// Wrapper around AppService.
// Provides abstraction layer for Per-App Time Limits (PATL). Takes care of
// types conversions and data filetering, so those operations are not spread
// around the PATL code.
class AppServiceWrapper : public apps::AppRegistryCache::Observer,
                          public apps::InstanceRegistry::Observer {
 public:
  // Notifies listeners about app state changes.
  // Listener only get updates about apps that are relevant for PATL feature.
  class EventListener : public base::CheckedObserver {
   public:
    // Called when app with |app_id| is installed and at the beginning of each
    // user session (because AppService does not store apps information between
    // sessions).
    virtual void OnAppInstalled(const AppId& app_id) {}

    // Called when app with |app_id| is uninstalled.
    virtual void OnAppUninstalled(const AppId& app_id) {}

    // Called when app with |app_id| become available for usage. Usually when
    // app is unblocked.
    virtual void OnAppAvailable(const AppId& app_id) {}

    // Called when app with |app_id| become disabled and cannot be used.
    virtual void OnAppBlocked(const AppId& app_id) {}

    // Called when app with |app_id| becomes active.
    // Active means that the app is in usage (visible in foreground).
    // If the app is launched multiple times, |instance_id| indicates which
    // of the instances is active.
    // |timestamp| indicates the time when the app became active.
    virtual void OnAppActive(const AppId& app_id,
                             const base::UnguessableToken& instance_id,
                             base::Time timestamp) {}

    // Called when app with |app_id| becomes inactive.
    // Inactive means that the app is not in the foreground. It still can run
    // and be partially visible. |timestamp| indicates the time when the app
    // became inactive. |instance_id| to specify which of the application's
    // potentially multiple instances became inactive. Note: This can be called
    // for the app that is already inactive.
    virtual void OnAppInactive(const AppId& app_id,
                               const base::UnguessableToken& instance_id,
                               base::Time timestamp) {}

    // Called when app with |app_id| is destroyed.
    // |timestamp| indicates the time when the app is destroyed.
    // |instance_id| to specify which of the application's potentially multiple
    // instances was destroyed.
    virtual void OnAppDestroyed(const AppId& app_id,
                                const base::UnguessableToken& instance_id,
                                base::Time timestamp) {}
  };

  explicit AppServiceWrapper(Profile* profile);
  AppServiceWrapper(const AppServiceWrapper&) = delete;
  AppServiceWrapper& operator=(const AppServiceWrapper&) = delete;
  ~AppServiceWrapper() override;

  // Pauses the app identified by |PauseAppInfo::app_id|.
  // Uses |PauseAppInfo::daily_limit| to communicate applied time restriction to
  // the user by showing the dialog. After this is called user will not be able
  // to launch the app and the visual effect will be applied to the icon.
  // |PauseAppInfo::show_pause_dialog| indicates whether the user should be
  // notified with a dialog.
  void PauseApp(const PauseAppInfo& pause_app);
  void PauseApps(const std::vector<PauseAppInfo>& paused_apps);

  // Resets time restriction from the app identified with |app_id|. After this
  // is called user will be able to use the app again and the visual effect
  // will be removed from the icon.
  void ResumeApp(const AppId& app_id);

  // Launches app identified by |app_service_id| with no event flags explicitly
  // and default display id.
  void LaunchApp(const std::string& app_service_id);

  // Returns installed apps that are relevant for Per-App Time Limits feature.
  // Installed apps of unsupported types will not be included.
  std::vector<AppId> GetInstalledApps() const;

  // Returns true if the application is a hidden arc++ app.
  bool IsHiddenArcApp(const AppId& app_id) const;

  // Returns the list of arc++ apps hidden from user.
  std::vector<AppId> GetHiddenArcApps() const;

  // Returns short name of the app identified by |app_id|.
  // Might return empty string.
  std::string GetAppName(const AppId& app_id) const;

  // Returns the uncompressed image icon for app identified by |app_id| with
  // size |size_hint_in_dp|.
  void GetAppIcon(const AppId& app_id,
                  int size_hint_in_dp,
                  base::OnceCallback<void(std::optional<gfx::ImageSkia>)>
                      on_icon_ready) const;

  // Returns app service id for the app identified by |app_id|.
  // App service id will be only different from app_id.app_id() for ARC++ apps.
  // It does not make sense to call it for other apps.
  std::string GetAppServiceId(const AppId& app_id) const;

  // Return true if the App with |app_service_id| is installed.
  bool IsAppInstalled(const std::string& app_service_id);

  // Returns AppId from |app_service_id| and |app_type|.
  AppId AppIdFromAppServiceId(const std::string& app_service_id,
                              apps::AppType app_type) const;

  void AddObserver(EventListener* observer);
  void RemoveObserver(EventListener* observer);

  // apps::AppRegistryCache::Observer:
  void OnAppUpdate(const apps::AppUpdate& update) override;
  void OnAppRegistryCacheWillBeDestroyed(
      apps::AppRegistryCache* cache) override;

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

  apps::InstanceRegistry& GetInstanceRegistry() const;

 private:
  apps::AppServiceProxy* GetAppProxy() const;
  apps::AppRegistryCache& GetAppCache() const;

  // Return whether app with |app_id| should be included for per-app time
  // limits.
  bool ShouldIncludeApp(const AppId& app_id) const;

  base::ObserverList<EventListener> listeners_;

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

  base::ScopedObservation<apps::AppRegistryCache,
                          apps::AppRegistryCache::Observer>
      app_registry_cache_observer_{this};

  const raw_ptr<Profile> profile_;
};

}  // namespace app_time
}  // namespace ash

#endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_SERVICE_WRAPPER_H_