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
  136
  137
  138
  139
  140
  141
  142
  143
  144

ash / ambient / model / ambient_backend_model.h [blame]

// 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 ASH_AMBIENT_MODEL_AMBIENT_BACKEND_MODEL_H_
#define ASH_AMBIENT_MODEL_AMBIENT_BACKEND_MODEL_H_

#include <string>
#include <vector>

#include "ash/ambient/ambient_constants.h"
#include "ash/ambient/model/ambient_photo_config.h"
#include "ash/ash_export.h"
#include "ash/public/cpp/ambient/ambient_backend_controller.h"
#include "base/containers/circular_deque.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "ui/gfx/image/image_skia.h"

namespace ash {

class AmbientBackendModelObserver;

// Contains each photo image and its metadata used to show on ambient.
struct ASH_EXPORT PhotoWithDetails {
  PhotoWithDetails();

  PhotoWithDetails(const PhotoWithDetails&);
  PhotoWithDetails& operator=(const PhotoWithDetails&);
  PhotoWithDetails(PhotoWithDetails&&);
  PhotoWithDetails& operator=(PhotoWithDetails&&);

  ~PhotoWithDetails();

  void Clear();
  bool IsNull() const;

  gfx::ImageSkia photo;
  gfx::ImageSkia related_photo;
  std::string details;
  std::string related_details;
  // Hash of this image data. Used for de-duping images.
  std::string hash;
  // Whether the image is portrait or not.
  bool is_portrait = false;
  ::ambient::TopicType topic_type = ::ambient::TopicType::kOther;
};

// Stores necessary information fetched from the backdrop server to render
// the photo frame in Ambient Mode. Owned by |AmbientController|.
class ASH_EXPORT AmbientBackendModel {
 public:
  explicit AmbientBackendModel(AmbientPhotoConfig photo_config);
  AmbientBackendModel(const AmbientBackendModel&) = delete;
  AmbientBackendModel& operator=(AmbientBackendModel&) = delete;
  ~AmbientBackendModel();

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

  // If enough images are loaded to start ambient mode.
  bool ImagesReady() const;

  // Add image to local storage.
  void AddNextImage(const PhotoWithDetails& photo);

  // Returns true if |hash| would cause an identical image to appear twice in a
  // row. For example:
  // {A, B} + B => true
  // {A, B} + A => false
  // {A, _} + B => false
  // {A, _} + A => true
  bool IsHashDuplicate(const std::string& hash) const;

  // Record that fetching an image has failed.
  void AddImageFailure();

  void ResetImageFailures();

  bool ImageLoadingFailed();

  // Clear local storage.
  void Clear();

  // Sets the new AmbientPhotoConfig to use. This automatically |Clear()|s the
  // model of any existing topics.
  void SetPhotoConfig(AmbientPhotoConfig photo_config);

  // Returns all available decoded topics. The number of decoded topics in the
  // output will always be <= |AmbientPhotoConfig.num_decoded_topics_to_buffer|.
  //
  // Every PhotoWithDetails instance in the output shall be non-null.
  const base::circular_deque<PhotoWithDetails>& all_decoded_topics() const {
    return all_decoded_topics_;
  }

  // Gets the 2 oldest decoded topics. It's possible to accomplish this as well
  // by calling GetAllAvailableDecodedTopics() directly, but this wrapper
  // function is provided as a convenience.
  //
  // If an output PhotoWithDetails argument is nullptr, that specific topic is
  // ignored and not fetched.
  //
  // If one of the requested topics is unavailable, its corresponding output
  // argument is set to an empty PhotoWithDetails instance.
  void GetCurrentAndNextImages(PhotoWithDetails* current_image_out,
                               PhotoWithDetails* next_image_out) const;

  base::TimeDelta GetPhotoRefreshInterval() const;

  const AmbientPhotoConfig& photo_config() const { return photo_config_; }

 private:
  friend class AmbientBackendModelTest;
  friend class AmbientAshTestBase;

  void NotifyImageAdded();
  void NotifyImagesReady();
  void OnImagesReadyTimeoutFired();

  AmbientPhotoConfig photo_config_;
  std::vector<AmbientModeTopic> topics_;

  // All available decoded topics. The size of the ring buffer is capped
  // according to |AmbientPhotoConfig.num_decoded_topics_to_buffer|. The most
  // recently decoded topics are pushed to the back of the ring buffer and the
  // oldest topics are popped from the front.
  base::circular_deque<PhotoWithDetails> all_decoded_topics_;

  base::OneShotTimer images_ready_timeout_timer_;
  bool images_ready_timed_out_ = false;

  // The number of consecutive failures to load the next image.
  int failures_ = 0;

  base::ObserverList<AmbientBackendModelObserver> observers_;

  int buffer_length_for_testing_ = -1;
};

}  // namespace ash

#endif  // ASH_AMBIENT_MODEL_AMBIENT_BACKEND_MODEL_H_