summaryrefslogtreecommitdiffstats
path: root/components/search_provider_logos/logo_tracker.h
blob: 29933eb611093bd6d0ce52b90d87e3aedee98634 (plain)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_
#define COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_

#include <string>
#include <vector>

#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequenced_task_runner.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "components/search_provider_logos/logo_cache.h"
#include "components/search_provider_logos/logo_common.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"

namespace net {
class URLFetcher;
class URLRequestContextGetter;
}

namespace search_provider_logos {

// Receives updates when the search provider's logo is available.
class LogoObserver {
 public:
  virtual ~LogoObserver() {}

  // Called when the cached logo is available and possibly when a freshly
  // downloaded logo is available. |logo| will be NULL if no logo is available.
  // |from_cache| indicates whether the logo was loaded from the cache.
  //
  // If the fresh logo is the same as the cached logo, this will not be called
  // again.
  virtual void OnLogoAvailable(const Logo* logo, bool from_cache) = 0;

  // Called when the LogoTracker will no longer send updates to this
  // LogoObserver. For example: after the cached logo is validated, after
  // OnFreshLogoAvailable() is called, or when the LogoTracker is destructed.
  // This is not called when an observer is removed using
  // LogoTracker::RemoveObserver().
  virtual void OnObserverRemoved() = 0;
};

// Provides a LogoTracker with methods it needs to download and cache logos.
class LogoDelegate {
 public:
  virtual ~LogoDelegate() {}

  // Decodes an untrusted image safely and returns it as an SkBitmap via
  // |image_decoded_callback|. If image decoding fails, |image_decoded_callback|
  // should be called with NULL. This will be called on the thread that
  // LogoTracker lives on and |image_decoded_callback| must be called on the
  // same thread.
  virtual void DecodeUntrustedImage(
      const scoped_refptr<base::RefCountedString>& encoded_image,
      base::Callback<void(const SkBitmap&)> image_decoded_callback) = 0;
};

// Parses the response from the server and returns it as an EncodedLogo. Returns
// NULL if the response is invalid.
typedef base::Callback<
    scoped_ptr<EncodedLogo>(const scoped_ptr<std::string>& response,
                            base::Time response_time)> ParseLogoResponse;

// Encodes the fingerprint of the cached logo in the logo URL. This enables the
// server to verify whether the cached logo is up-to-date.
typedef base::Callback<GURL(const GURL& logo_url,
                            const std::string& fingerprint,
                            bool wants_cta)> AppendQueryparamsToLogoURL;

// This class provides the logo for a search provider. Logos are downloaded from
// the search provider's logo URL and cached on disk.
//
// Call SetServerAPI() at least once to specify how to get the logo from the
// server. Then call GetLogo() to trigger retrieval of the logo and receive
// updates once the cached and/or fresh logos are available.
class LogoTracker : public net::URLFetcherDelegate {
 public:
  // Constructs a LogoTracker with the given LogoDelegate. Takes ownership of
  // |delegate|, which will be deleted at the same time as the LogoTracker.
  //
  // |cached_logo_directory| is the directory in which the cached logo and its
  // metadata should be saved.
  //
  // |file_task_runner| is the SequencedTaskRunner that should be used to run
  // file system operations.
  //
  // |background_task_runner| is the TaskRunner that should be used to for
  // CPU-intensive background operations.
  //
  // |request_context_getter| is the URLRequestContextGetter used to download
  // the logo.
  explicit LogoTracker(
      base::FilePath cached_logo_directory,
      scoped_refptr<base::SequencedTaskRunner> file_task_runner,
      scoped_refptr<base::TaskRunner> background_task_runner,
      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
      scoped_ptr<LogoDelegate> delegate);

  ~LogoTracker() override;

  // Defines the server API for downloading and parsing the logo. This must be
  // called at least once before calling GetLogo().
  //
  // |logo_url| is the URL from which the logo will be downloaded. If |logo_url|
  // is different than the current logo URL, any pending LogoObservers will be
  // canceled.
  //
  // |parse_logo_response_func| is a callback that will be used to parse the
  // server's response into a EncodedLogo object. |append_queryparams_func| is a
  // callback that will return the URL from which to download the logo.
  // |wants_cta| determines if the url should return a call to action image.
  // Note: |parse_logo_response_func| and |append_queryparams_func| must be
  // suitable for running multiple times, concurrently, and on multiple threads.
  void SetServerAPI(const GURL& logo_url,
                    const ParseLogoResponse& parse_logo_response_func,
                    const AppendQueryparamsToLogoURL& append_queryparams_func,
                    bool wants_cta);

  // Retrieves the current search provider's logo from the local cache and/or
  // over the network, and registers |observer| to be called when the cached
  // and/or fresh logos are available.
  void GetLogo(LogoObserver* observer);

  // Prevents |observer| from receiving future updates. This is safe to call
  // even when the observer is being notified of an update.
  void RemoveObserver(LogoObserver* observer);

  // Overrides the cache used to store logos.
  void SetLogoCacheForTests(scoped_ptr<LogoCache> cache);

  // Overrides the clock used to check the time.
  void SetClockForTests(scoped_ptr<base::Clock> clock);

 private:
  // Cancels the current asynchronous operation, if any, and resets all member
  // variables that change as the logo is fetched.
  void ReturnToIdle();

  // Called when the cached logo has been read from the cache. |cached_logo|
  // will be NULL if there wasn't a valid, up-to-date logo in the cache.
  void OnCachedLogoRead(scoped_ptr<EncodedLogo> cached_logo);

  // Called when the cached logo has been decoded into an SkBitmap. |image| will
  // be NULL if decoding failed.
  void OnCachedLogoAvailable(const LogoMetadata& metadata,
                             const SkBitmap& image);

  // Stores |logo| in the cache.
  void SetCachedLogo(scoped_ptr<EncodedLogo> logo);

  // Updates the metadata for the logo already stored in the cache.
  void SetCachedMetadata(const LogoMetadata& metadata);

  // Starts fetching the current logo over the network.
  void FetchLogo();

  // Called when the logo has been downloaded and parsed. |logo| will be NULL
  // if the server's response was invalid.
  void OnFreshLogoParsed(scoped_ptr<EncodedLogo> logo);

  // Called when the fresh logo has been decoded into an SkBitmap. |image| will
  // be NULL if decoding failed.
  void OnFreshLogoAvailable(scoped_ptr<EncodedLogo> logo,
                            const SkBitmap& image);

  // net::URLFetcherDelegate:
  void OnURLFetchComplete(const net::URLFetcher* source) override;
  void OnURLFetchDownloadProgress(const net::URLFetcher* source,
                                  int64 current,
                                  int64 total) override;

  // The URL from which the logo is fetched.
  GURL logo_url_;

  // The function used to parse the logo response from the server.
  ParseLogoResponse parse_logo_response_func_;

  // The function used to include the cached logo's fingerprint and call to
  // action request in the logo URL.
  AppendQueryparamsToLogoURL append_queryparams_func_;

  // If |true| request call to action in server API.
  bool wants_cta_;

  // False if an asynchronous task is currently running.
  bool is_idle_;

  // The logo that's been read from the cache, or NULL if the cache is empty.
  // Meaningful only if is_cached_logo_valid_ is true; NULL otherwise.
  scoped_ptr<Logo> cached_logo_;

  // Whether the value of |cached_logo_| reflects the actual cached logo.
  // This will be false if the logo hasn't been read from the cache yet.
  // |cached_logo_| may be NULL even if |is_cached_logo_valid_| is true, if no
  // logo is cached.
  bool is_cached_logo_valid_;

  // The URLFetcher currently fetching the logo. NULL when not fetching.
  scoped_ptr<net::URLFetcher> fetcher_;

  // The list of observers to be notified when the logo is available. This
  // should be empty when the state is IDLE.
  base::ObserverList<LogoObserver> logo_observers_;

  scoped_ptr<LogoDelegate> logo_delegate_;

  // The cache used to persist the logo on disk. Used only on the file thread.
  LogoCache* logo_cache_;

  // Clock used to determine current time. Can be overridden in tests.
  scoped_ptr<base::Clock> clock_;

  // The SequencedTaskRunner on which file system operations will be run.
  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;

  // The TaskRunner on which the server's response will be parsed.
  scoped_refptr<base::TaskRunner> background_task_runner_;

  // The URLRequestContextGetter used for network requests.
  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;

  base::WeakPtrFactory<LogoTracker> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(LogoTracker);
};

}  // namespace search_provider_logos

#endif  // COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_