1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135

ash / ambient / ambient_managed_photo_controller.h [blame]

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_AMBIENT_AMBIENT_MANAGED_PHOTO_CONTROLLER_H_
#define ASH_AMBIENT_AMBIENT_MANAGED_PHOTO_CONTROLLER_H_

#include <vector>

#include "ash/ambient/model/ambient_backend_model.h"
#include "ash/ambient/model/ambient_photo_config.h"
#include "ash/ambient/ui/ambient_view_delegate.h"
#include "ash/ash_export.h"
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"

namespace gfx {
class ImageSkia;
}  // namespace gfx

namespace ash {

// Class to handle policy-set photos in ambient mode. This is a barebones
// controller which takes in a list of file paths and adds them to the backend
// model one by one.
class ASH_EXPORT AmbientManagedPhotoController
    : public AmbientViewDelegateObserver {
 public:
  class ASH_EXPORT Observer {
   public:
    virtual void OnErrorStateChanged() {}
  };

  AmbientManagedPhotoController(AmbientViewDelegate& view_delegate,
                                AmbientPhotoConfig photo_config);

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

  ~AmbientManagedPhotoController() override;

  // Start/stop updating the screen contents.
  void StartScreenUpdate();
  void StopScreenUpdate();
  bool IsScreenUpdateActive() const;
  bool HasScreenUpdateErrors() const;

  void SetObserver(Observer* observer);

  // Updates the image file paths, if controller is active, this method will
  // also load these files from disk and put them in backend model in case the
  // controller is in the active state.
  void UpdateImageFilePaths(const std::vector<base::FilePath>& path_to_images);

  AmbientBackendModel* ambient_backend_model() {
    return &ambient_backend_model_;
  }
  // AmbientViewDelegateObserver:
  void OnMarkerHit(AmbientPhotoConfig::Marker marker) override;

 private:
  // The controller `state_` is reset on dismissing the screensaver (when
  // StopScreenUpdate is called) so if the error states are not treated
  // differently they will be cleared on dismissing the screensaver and we will
  // waste CPU cycles going in and out of this Started->Error state.
  // Treating the error state separately allows the error state to be sticky and
  // lets us know when there are still errors when the data doesn't change.
  enum class ErrorState {
    kNone,
    // The controller was started with an insufficient number of images.
    kInsufficientImages,
    // The controller was started but we failed to load a sufficient number of
    // images to continue even after trying to load all the provided images from
    // disk.
    kPhotoLoadFailure,
  };

  // Load and decode images
  void LoadImages();
  size_t GetMaxImageAttempts() const;

  // Loads `images_to_load` no of images in an asynchronous but sequential
  // manner and waits for the previous image to load before starting to load the
  // next image. `success` denotes that the previous load was successful. Note:
  // In case `success` is false or `images_to_load` is 0 this method will be  a
  // no-op.
  void LoadImagesInternal(size_t images_to_load, bool success);
  void LoadNextImage(base::OnceCallback<void(bool success)> callback);
  void OnPhotoDecoded(base::OnceCallback<void(bool success)> callback,
                      const gfx::ImageSkia& image);
  void HandlePhotoDecodingFailure(
      base::OnceCallback<void(bool success)> callback);

  // Sets and notifies whenever the `error_state_` is changed.
  void SetErrorState(ErrorState error_state);

  AmbientBackendModel ambient_backend_model_;

  // The current number of tries for loading the next image, once it reaches the
  // max tries, we will log an error and stop retrying. This is reset as soon as
  // an image is decoded successfully.
  size_t image_attempt_no_ = 0;

  // Current index of cached file to read and display.
  size_t current_image_index_ = 0;

  // Flag used to determine whether the screen update is active. The screen
  // update is considered to be active when the `StartScreenUpdate` method has
  // been called. And it stops being active when the `StopScreenUpdate` method
  // is called.
  bool is_active_ = false;

  // State used to determine whether the controller has encountered any errors.
  // Note: This is sticky and cleared when sufficient new data is added to the
  // controller.
  ErrorState error_state_ = ErrorState::kNone;

  // The list of image filepaths that are used as the sources for the images to
  // show.
  std::vector<base::FilePath> images_file_paths_;

  raw_ptr<Observer> observer_ = nullptr;

  base::ScopedObservation<AmbientViewDelegate, AmbientViewDelegateObserver>
      scoped_view_delegate_observation_{this};

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

}  // namespace ash

#endif  // ASH_AMBIENT_AMBIENT_MANAGED_PHOTO_CONTROLLER_H_