| // 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 <stdint.h> |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/callback.h" |
| #include "base/files/file_path.h" |
| #include "base/macros.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, |
| bool* parsing_failed)> 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. |
| // TODO(ianwen): remove wants_cta from parameter. |
| 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: |
| |
| // These values must stay in sync with the NewTabPageLogoDownloadOutcome enum |
| // in histograms.xml. And any addtion should be treated as append-only! |
| // Animated doodle is not covered by this enum. |
| enum LogoDownloadOutcome { |
| DOWNLOAD_OUTCOME_NEW_LOGO_SUCCESS, |
| DOWNLOAD_OUTCOME_NO_LOGO_TODAY, |
| DOWNLOAD_OUTCOME_DOWNLOAD_FAILED, |
| DOWNLOAD_OUTCOME_PARSING_FAILED, |
| DOWNLOAD_OUTCOME_DECODING_FAILED, |
| DOWNLOAD_OUTCOME_LOGO_REVALIDATED, |
| DOWNLOAD_OUTCOME_COUNT, |
| }; |
| |
| const int kDownloadOutcomeNotTracked = -1; |
| |
| // Cancels the current asynchronous operation, if any, and resets all member |
| // variables that change as the logo is fetched. This method also records UMA |
| // histograms for for the given LogoDownloadOutcome. |
| void ReturnToIdle(int outcome); |
| |
| // 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(bool* parsing_failed, 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, |
| bool parsing_failed, |
| const SkBitmap& image); |
| |
| // net::URLFetcherDelegate: |
| void OnURLFetchComplete(const net::URLFetcher* source) override; |
| void OnURLFetchDownloadProgress(const net::URLFetcher* source, |
| int64_t current, |
| int64_t 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 timestamp for the last time a logo is stated to be downloaded. |
| base::TimeTicks logo_download_start_time_; |
| |
| // 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_ |