chromium/chrome/browser/ash/child_accounts/time_limits/app_types.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_TYPES_H_
#define CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_TYPES_H_

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

#include "base/time/time.h"
#include "components/services/app_service/public/cpp/app_types.h"

namespace ash {
namespace app_time {

// Type of usage restriction that can be applied to the installed app.
enum class AppRestriction {
  kUnknown,
  // Installed app is not available for the user.
  kBlocked,
  // Daily time limit is enforced. Installed app will become unavailable for
  // the user after time limit is reached on a given day.
  kTimeLimit,
};

// State of the app. Used for activity recording and status reporting. The enum
// values are persisted in user pref service. Existing values should never be
// deleted or reordered. New states should be appended at the end.
enum class AppState {
  // App is available for the user.
  kAvailable = 0,
  // App cannot be restricted. Used for important system apps.
  kAlwaysAvailable = 1,
  // App is not available for the user because of being blocked.
  kBlocked = 2,
  // App is not available for the user because daily time limit was reached.
  kLimitReached = 3,
  // App is uninstalled. Activity might still be preserved and reported for
  // recently uninstalled apps.
  kUninstalled = 4,
};

// Type of notification to show the child user.
enum class AppNotification {
  kUnknown,

  // Five minutes left before the application's time limit is reached.
  kFiveMinutes,

  // One minjute left before the application's time limit is reached.
  kOneMinute,

  // Application's time limit reached.
  kTimeLimitReached,

  // Application's time limit has been updated by parents.
  kTimeLimitChanged,

  // Application is blocked.
  kBlocked,

  // Application is unblocked.
  kAvailable
};

enum class ChromeAppActivityState {
  // The browser is active and hosts urls in its active tab which are not
  // allowlisted.
  kActive,

  // Same as |kActive| except the urls the browser hosts are allowlisted.
  kActiveAllowlisted,

  // The browser window is not active.
  kInactive,
};

// Identifies an app for app time limits.
// Different types of use different identifier format. ARC++ apps are identified
// by Android package name. Other types of apps use 32 character long Chrome
// specific app id.
class AppId {
 public:
  AppId(apps::AppType app_type, const std::string& app_id);
  AppId(const AppId&);
  AppId& operator=(const AppId&);
  AppId(AppId&&);
  AppId& operator=(AppId&&);
  ~AppId();

  apps::AppType app_type() const { return app_type_; }
  const std::string& app_id() const { return app_id_; }

  bool operator==(const AppId&) const;
  bool operator!=(const AppId&) const;
  bool operator<(const AppId&) const;
  friend std::ostream& operator<<(std::ostream&, const AppId&);

 private:
  apps::AppType app_type_ = apps::AppType::kUnknown;

  // Package name for |ARC| apps, 32 character long Chrome specific app id
  // otherwise.
  std::string app_id_;
};

struct PauseAppInfo {
  PauseAppInfo(const AppId& app, base::TimeDelta limit, bool show_dialog);

  AppId app_id;
  base::TimeDelta daily_limit;
  bool show_pause_dialog = true;
};

// Represents restriction that can be applied to an installed app.
class AppLimit {
 public:
  // Creates AppLimit.
  // |daily_limit| can only be set when |restriction| is kTimeLimit.
  // |daily_limit| needs to be in range of [0, 24] hours.
  AppLimit(AppRestriction restriction,
           std::optional<base::TimeDelta> daily_limit,
           base::Time last_updated);
  AppLimit(const AppLimit&);
  AppLimit& operator=(const AppLimit&);
  AppLimit(AppLimit&&);
  AppLimit& operator=(AppLimit&&);
  ~AppLimit();

  AppRestriction restriction() const { return restriction_; }
  base::Time last_updated() const { return last_updated_; }
  const std::optional<base::TimeDelta>& daily_limit() const {
    return daily_limit_;
  }

 private:
  // Usage restriction applied to the app.
  AppRestriction restriction_ = AppRestriction::kUnknown;

  // Daily usage limit. Only set |restriction| is kTimeLimit.
  // Has to be between 0 and 24 hours.
  std::optional<base::TimeDelta> daily_limit_;

  // UTC timestamp for the last time the limit was updated.
  base::Time last_updated_;
};

// Contains information about app usage.
class AppActivity {
 public:
  class ActiveTime {
   public:
    static const base::TimeDelta kActiveTimeMergePrecision;

    // If |t1| and |t2| overlap or are within |kActiveTimeMergePrecision| of
    // each other, this static method creates a new ActiveTime with the earlier
    // of |t1|'s or |t2|'s |active_from| and the later of |t1|'s or |t2|'s
    // |active_to_|.
    static std::optional<ActiveTime> Merge(const ActiveTime& t1,
                                           const ActiveTime& t2);

    ActiveTime(base::Time start, base::Time end);
    ActiveTime(const ActiveTime& rhs);
    ActiveTime& operator=(const ActiveTime& rhs);

    bool operator==(const ActiveTime&) const;
    bool operator!=(const ActiveTime&) const;

    // Returns whether |timestamp| is included in this time period.
    bool Contains(base::Time timestamp) const;

    // Returns whether |timestamp| is earlier than this time period's start.
    bool IsEarlierThan(base::Time timestamp) const;

    // Returns whether |timestamp| is later than this time period's end.
    bool IsLaterThan(base::Time timestamp) const;

    base::Time active_from() const { return active_from_; }
    void set_active_from(base::Time active_from);
    base::Time active_to() const { return active_to_; }
    void set_active_to(base::Time active_to);

   private:
    base::Time active_from_;
    base::Time active_to_;
  };

  // Creates AppActivity and sets current |app_state_|.
  explicit AppActivity(AppState app_state);
  AppActivity(AppState app_state, base::TimeDelta running_active_time);
  AppActivity(const AppActivity&);
  AppActivity& operator=(const AppActivity&);
  AppActivity(AppActivity&&);
  AppActivity& operator=(AppActivity&&);
  ~AppActivity();

  void SetAppState(AppState app_state);
  void SetAppActive(base::Time timestamp);
  void SetAppInactive(base::Time timestamp);

  // Called when reset time has been reached.
  // Resets |running_active_time_|.
  // If the application is currently running, uses |timestamp| as current time
  // to log activity.
  void ResetRunningActiveTime(base::Time timestamp);

  base::TimeDelta RunningActiveTime() const;

  // Updates |active_times_| to include the current activity. If the app is
  // active, it saves the activitity until |timestamp|.
  void CaptureOngoingActivity(base::Time timestamp);

  // Caller takes ownership of |active_times_| i.e. |active_times_| is moved and
  // thus becomes empty after this method is called. Called from
  // AppActivityRegistry::SaveAppActivity when the app activity is going to be
  // saved in user preference.
  std::vector<ActiveTime> TakeActiveTimes();

  bool is_active() const { return is_active_; }
  AppState app_state() const { return app_state_; }
  const std::vector<ActiveTime>& active_times() const { return active_times_; }
  AppNotification last_notification() const { return last_notification_; }

  void set_last_notification(AppNotification notification) {
    last_notification_ = notification;
  }

  // Chrome and web apps share the same time limit. Therefore, we need to have a
  // consistent |running_active_time_| across all web apps and chrome.
  void set_running_active_time(base::TimeDelta time) {
    DCHECK(!is_active_);
    running_active_time_ = time;
  }

 private:
  // boolean to specify if the application is active.
  bool is_active_ = false;

  AppNotification last_notification_ = AppNotification::kUnknown;

  // Current state of the app.
  // There might be relevant activity recoded for app that was uninstalled
  // recently.
  AppState app_state_ = AppState::kAvailable;

  // Keeps the sum of the active times since the last reset.
  base::TimeDelta running_active_time_;

  // The time app was active.
  std::vector<ActiveTime> active_times_;

  // Time tick for the last time the activity was updated.
  base::TimeTicks last_updated_time_ticks_;
};

}  // namespace app_time
}  // namespace ash

#endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_TYPES_H_