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_