Index: chrome/browser/installable/installable_checker.h |
diff --git a/chrome/browser/installable/installable_checker.h b/chrome/browser/installable/installable_checker.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f41b5c045249bd197e141d10cf05fd7043516f7c |
--- /dev/null |
+++ b/chrome/browser/installable/installable_checker.h |
@@ -0,0 +1,265 @@ |
+// Copyright 2016 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 CHROME_BROWSER_INSTALLABLE_INSTALLABLE_CHECKER_H_ |
+#define CHROME_BROWSER_INSTALLABLE_INSTALLABLE_CHECKER_H_ |
+ |
+#include <utility> |
+ |
+#include "base/callback_forward.h" |
+#include "base/gtest_prod_util.h" |
+#include "base/macros.h" |
+#include "base/memory/weak_ptr.h" |
+#include "chrome/browser/installable/installable_logging.h" |
+#include "content/public/browser/web_contents_observer.h" |
+#include "content/public/browser/web_contents_user_data.h" |
+#include "content/public/common/manifest.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "url/gurl.h" |
+ |
+namespace installable { |
+ |
+// This struct specifies the work to be done by the InstallableChecker on the |
+// site loaded in the main frame of the WebContents to which it is attached. |
+// Results are cached and evaluated the order specified in this struct; if any |
+// previous step is requested and fails, no further steps will be performed. |
+// For example, if |has_valid_icon| and |has_service_worker| are both true, |
+// then the site's icon will only be fetched if a service worker was found. |
+// The checker will *always* look for a web app manifest first as this is |
+// required for all other resources. |
+struct InstallableParams { |
+ // The ideal icon size that should be fetched. Used only if |has_valid_icon| |
+ // is true. |
+ int ideal_icon_size_in_dp; |
+ |
+ // The minimum icon size that should be fetched. Used only if |
+ // |has_valid_icon| is true. |
+ int minimum_icon_size_in_dp; |
+ |
+ // Check whether the site's manifest is valid for a web app. That is, the |
+ // manifest: |
+ // - is non-empty |
+ // - has a valid start URL |
+ // - has a non-null name OR a non-null short_name |
+ // - has a display field set to "standalone" or "fullscreen" |
+ // - contains a PNG icon of at least 144x144px |
+ bool has_valid_webapp_manifest; |
+ |
+ // Check whether the site has an active service worker controlling it and the |
+ // manifest start URL. |
+ bool has_service_worker; |
+ |
+ // Check whether there is an icon in the manifest conforming to the icon size |
+ // parameters, and that the icon can be fetched and isn't an empty bitmap. |
+ bool has_valid_icon; |
+ |
+ // The default constructor sets all bool parameters are set to false. |
+ InstallableParams(); |
+}; |
+ |
+// This struct is passed to an InstallableCallback when the InstallableChecker |
+// has finished working. Each pointer/reference member is a reference to the |
+// data in InstallableChecker; the checker owns these resources. |
+// Callers should ensure that all fields they use in this result struct are |
+// requested in the original call to InstallableChecker::Start. |
+struct InstallableResult { |
+ // This code will be NoErrorDetected if there were no issues. |
+ const ErrorCode error_code; |
+ |
+ // The manifest URL. If non-empty, the site specified a <link rel="manifest"> |
+ // tag. |
+ const GURL& manifest_url; |
+ |
+ // The manifest object. Empty if a manifest was not specified, or could not be |
+ // parsed. |
+ const content::Manifest& manifest; |
+ |
+ // The URL of the most appropriate icon from the manifest. |
+ const GURL& icon_url; |
+ |
+ // The most appropriate icon from the manifest. |
+ const SkBitmap* icon; |
+ |
+ // True if the site has a manifest which is valid for a webapp. |
+ const bool has_valid_webapp_manifest; |
+ |
+ // True if the site has a service worker controlling the manifest start URL. |
+ const bool has_service_worker; |
+}; |
+ |
+// The callback type passed to InstallableChecker::Start. Invoked on the UI |
+// thread once the checker has performed all of the operations specified in the |
+// InstallableParams passed to Start. |
+using InstallableCallback = base::Callback<void(const InstallableResult&)>; |
+ |
+// This class is responsible for fetching the resources required to check and |
+// install a site. Minimally, this is a web app manifest for the document in the |
+// main frame; this manifest is all that is required for a site offering native |
+// app banners. Progressive web apps must have specific fields in the manifest |
+// set, a service worker controlling the manifest's start URL, and a valid, |
+// fetchable icon in the manifest. Sites which do not have a service worker may |
+// still specify a valid, fetchable icon in the manifest, and this will be used |
+// when the site is added to homescreen. |
+class InstallableChecker |
+ : public content::WebContentsObserver, |
+ public content::WebContentsUserData<InstallableChecker> { |
+ public: |
+ explicit InstallableChecker(content::WebContents* web_contents); |
+ ~InstallableChecker() override; |
+ |
+ // Returns true if the InstallableChecker is currently running. |
+ bool IsActive() const { return HasFlag(STARTED); } |
+ |
+ // Returns true if |manifest| meets the requirements for being installable. |
+ // Sets |valid_webapp_manifest_error_| if any errors are encountered. |
+ bool IsManifestValidForWebApp(const content::Manifest& manifest); |
+ |
+ // Returns the minimum icon size in pixels for a site to be installable. |
+ // TODO(dominickn): consolidate this concept with minimum_icon_size_in_dp |
+ // across all platforms. |
+ static int GetMinimumIconSizeInPx(); |
+ |
+ // Start the installable check, fetching the resources specified in |params|. |
+ // |callback| is invoked on the UI thread when the checks are complete, |
+ // passing an InstallableResult struct containing the requested resources. |
+ // |
+ // Separate calls to Start are processed serially; each call is guaranteed to |
+ // invoke |callback| before the next one is processed. Resources are cached on |
+ // this object: a previous call for the same page and with the same icon sizes |
+ // will not perform duplicate work and will run the callback immediately with |
+ // the cached resources. When |callback| runs, it should copy any resources on |
+ // the result that are necessary for future work. It should also avoid running |
+ // expensive tasks directly and defer them to later as the callback is |
+ // directly invoked by the InstallableChecker to guarantee the consistency of |
+ // the check results (i.e. the icon). |
+ // This method is marked virtual so clients may mock this object in tests. |
+ virtual void Start(const InstallableParams& params, |
+ const InstallableCallback& callback); |
+ |
+ private: |
+ friend class InstallableCheckerUnitTest; |
+ FRIEND_TEST_ALL_PREFIXES(InstallableCheckerBrowserTest, |
+ CheckerBeginsInEmptyState); |
+ FRIEND_TEST_ALL_PREFIXES(InstallableCheckerBrowserTest, |
+ CheckWebapp); |
+ |
+ // This pair holds the parameters for a request to Start, along with the |
+ // callback to be invoked when the request parameters are fulfilled. This is |
+ // cheaply copyable and will be held in a std::vector. |
+ using Task = std::pair<InstallableParams, InstallableCallback>; |
+ |
+ // Bit flags used to maintain internal state regarding what has and hasn't yet |
+ // been fetched/computed. |
+ enum StatusFlag : uint32_t { |
+ DORMANT = 0, |
+ STARTED = 1 << 0, |
+ RUNNING_CALLBACKS = 1 << 1, |
+ MANIFEST_FETCHED = 1 << 2, |
+ MANIFEST_VALIDATED = 1 << 3, |
+ ICON_FETCHED = 1 << 4, |
+ SERVICE_WORKER_CHECKED = 1 << 5, |
+ }; |
+ |
+ // Stops the checking pipeline for the current task. Does not cancel any other |
+ // tasks which may be queued. |
+ void Cancel(); |
+ |
+ // Returns true if the icon size in |params| match those currently being |
+ // requested. |
+ bool DoesIconSizeMatch(const InstallableParams& params) const; |
+ |
+ // Returns the error code associated with the resources requested in |params|, |
+ // or NoErrorDetected if there is no error. |
+ ErrorCode GetErrorCode(const InstallableParams& params); |
+ |
+ // Returns the WebContents to which this object is attached, or nullptr if the |
+ // WebContents doesn't exist or is currently being destroyed. |
+ content::WebContents* GetWebContents(); |
+ |
+ // Returns true if |params| requires no more work to be done (i.e. all the |
+ // resources originally requested by |params| have been retrieved). |
+ bool IsComplete(const InstallableParams& params) const; |
+ |
+ // Returns true if |web_contents| is non-null and this checker remains active. |
+ // If false is returned, |processing_error_| will be set. |
+ bool IsRunning(content::WebContents* web_contents); |
+ |
+ // Resets this object and removes all queued tasks. Called when navigating to |
+ // a new page. |
+ void Reset(); |
+ |
+ // Runs the callback associated with any task that is now complete. |
+ void RunCallbacks(); |
+ |
+ // Runs the callbacks for any completed tasks, and starts work on the next. |
+ void StartTask(); |
+ |
+ // Sets |flag| bit in |status_| to 0 and 1 respectively. |
+ void ClearFlag(StatusFlag flag) { status_ &= ~flag; } |
+ void SetFlag(StatusFlag flag) { status_ |= flag; } |
+ |
+ // Returns true if the current status has the |flag| bit set to 1. |
+ bool HasFlag(StatusFlag flag) const { return (status_ & flag) != 0; } |
+ |
+ // Fetches the next required resource. |
+ void FetchResource(); |
+ |
+ // Data retrieval methods. |
+ void FetchManifest(); |
+ void OnDidGetManifest(const GURL& manifest_url, |
+ const content::Manifest& manifest); |
+ |
+ void CheckValidWebappManifest(); |
+ |
+ void CheckServiceWorker(); |
+ void OnDidCheckHasServiceWorker(bool has_service_worker); |
+ |
+ void ExtractAndFetchBestIcon(); |
+ void OnAppIconFetched(const GURL icon_url, const SkBitmap& bitmap); |
+ |
+ // content::WebContentsObserver overrides |
+ void DidFinishNavigation(content::NavigationHandle* handle) override; |
+ void WebContentsDestroyed() override; |
+ |
+ // Internal status field to keep track of what resources have been retrieved. |
+ uint32_t status_; |
+ |
+ // Error codes for each resource retrieval operation. |
+ ErrorCode processing_error_; |
+ ErrorCode manifest_error_; |
+ ErrorCode valid_webapp_manifest_error_; |
+ ErrorCode service_worker_error_; |
+ ErrorCode icon_error_; |
+ |
+ // The list of params + callback pairs that have come from a call to Start. |
+ std::vector<Task> tasks_; |
+ |
+ // Tasks received while we are currently working. These are held separately to |
+ // avoid contaminating the tasks_ vector (e.g. if a new Task is received |
+ // during RunCallbacks, e.g. an InstallableCallback is invoked which calls |
+ // Start), we cannot add it to tasks_ as the vector may be modified). |
+ std::vector<Task> pending_tasks_; |
+ |
+ // The icon size parameters used if a valid icon was requested. |
+ int ideal_icon_size_in_dp_; |
+ int minimum_icon_size_in_dp_; |
+ |
+ // Installable properties cached on this object. |
+ GURL manifest_url_; |
+ content::Manifest manifest_; |
+ GURL icon_url_; |
+ std::unique_ptr<SkBitmap> icon_; |
+ bool has_valid_webapp_manifest_; |
+ bool has_service_worker_; |
+ |
+ // This object has a lifetime scoped to a WebContents, so WeakPtrs can be used |
+ // for binding callbacks. |
+ base::WeakPtrFactory<InstallableChecker> weak_factory_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(InstallableChecker); |
+}; |
+ |
+} // namespace installable |
+ |
+#endif // CHROME_BROWSER_INSTALLABLE_INSTALLABLE_CHECKER_H_ |