summaryrefslogtreecommitdiffstats
path: root/chrome/browser/banners/app_banner_data_fetcher.h
blob: 194bf0b7f53f4bd56335241d86b739b8021a6275 (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
// Copyright 2015 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_BANNERS_APP_BANNER_DATA_FETCHER_H_
#define CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_H_

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "chrome/common/web_application_info.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/manifest.h"
#include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerPromptReply.h"

namespace chrome {
class BitmapFetcher;
}  // namespace chrome

namespace infobars {
class InfoBar;
}  // namespace infobars

namespace banners {
class AppBannerDataFetcher;

// Fetches data required to show a web app banner for the URL currently shown by
// the WebContents.
class AppBannerDataFetcher : public base::RefCountedThreadSafe<
                                 AppBannerDataFetcher,
                                 content::BrowserThread::DeleteOnUIThread>,
                             public content::WebContentsObserver {
 public:
  class Observer {
   public:
    virtual void OnDecidedWhetherToShow(AppBannerDataFetcher* fetcher,
                                        bool will_show) = 0;
    virtual void OnFetcherDestroyed(AppBannerDataFetcher* fetcher) = 0;
  };

  class Delegate {
   public:
    // Called to handle a non-web app. Returns |true| if the non-web app can be
    // handled, and the fetcher needs to remain active and wait for a callback.
    virtual bool HandleNonWebApp(const std::string& platform,
                                 const GURL& url,
                                 const std::string& id,
                                 bool is_debug_mode) = 0;
  };

  // Returns the current time.
  static base::Time GetCurrentTime();

  // Fast-forwards the current time for testing.
  static void SetTimeDeltaForTesting(int days);

  AppBannerDataFetcher(content::WebContents* web_contents,
                       base::WeakPtr<Delegate> weak_delegate,
                       int ideal_icon_size_in_dp,
                       int minimum_icon_size_in_dp,
                       bool is_debug_mode);

  // Begins creating a banner for the URL being displayed by the Delegate's
  // WebContents.
  void Start(const GURL& validated_url, ui::PageTransition transition_type);

  // Stops the pipeline when any asynchronous calls return.
  void Cancel();

  // Replaces the WebContents that is being observed.
  void ReplaceWebContents(content::WebContents* web_contents);

  // Adds an observer to the list.
  void AddObserverForTesting(Observer* observer);

  // Removes an observer from the list.
  void RemoveObserverForTesting(Observer* observer);

  // Returns whether or not the pipeline has been stopped.
  bool is_active() { return is_active_; }

  // Returns whether the beforeinstallprompt Javascript event was canceled.
  bool was_canceled_by_page() { return was_canceled_by_page_; }

  // Returns whether the page has validly requested that the banner be shown
  // by calling prompt() on the beforeinstallprompt Javascript event.
  bool page_requested_prompt() { return page_requested_prompt_; }

  // Returns true when it was created by the user action in DevTools or
  // "bypass-app-banner-engagement-checks" flag is set.
  bool is_debug_mode() const { return is_debug_mode_; }

  // Returns the type of transition which triggered this fetch.
  ui::PageTransition transition_type() { return transition_type_; }

  // Returns the URL that kicked off the banner data retrieval.
  const GURL& validated_url() { return validated_url_; }

  // WebContentsObserver overrides.
  void WebContentsDestroyed() override;
  void DidNavigateMainFrame(
      const content::LoadCommittedDetails& details,
      const content::FrameNavigateParams& params) override;
  bool OnMessageReceived(const IPC::Message& message,
                         content::RenderFrameHost* render_frame_host) override;

 protected:
  ~AppBannerDataFetcher() override;

  // Return a string describing what type of banner is being created. Used when
  // alerting websites that a banner is about to be created.
  virtual std::string GetBannerType();

  // Called after the manager sends a message to the renderer regarding its
  // intention to show a prompt. The renderer will send a message back with the
  // opportunity to cancel.
  void OnBannerPromptReply(content::RenderFrameHost* render_frame_host,
                           int request_id,
                           blink::WebAppBannerPromptReply reply,
                           std::string referrer);

  // Called when the client has prevented a banner from being shown, and is
  // now requesting that it be shown later.
  void OnRequestShowAppBanner(content::RenderFrameHost* render_frame_host,
                              int request_id);

  content::WebContents* GetWebContents();
  virtual std::string GetAppIdentifier();
  const content::Manifest& web_app_data() { return web_app_data_; }
  void set_app_title(const base::string16& title) { app_title_ = title; }
  int event_request_id() { return event_request_id_; }

  // Fetches the icon at the given URL asynchronously, returning |false| if a
  // load could not be started.
  bool FetchAppIcon(content::WebContents* web_contents, const GURL& url);

  // Records that a banner was shown. The |event_name| corresponds to the RAPPOR
  // metric being recorded.
  void RecordDidShowBanner(const std::string& event_name);

 private:
  // Callbacks for data retrieval.
  void OnDidHasManifest(bool has_manifest);
  void OnDidGetManifest(const content::Manifest& manifest);
  void OnDidCheckHasServiceWorker(bool has_service_worker);
  void OnAppIconFetched(const SkBitmap& bitmap);

  // Called when it is determined that the webapp has fulfilled the initial
  // criteria of having a manifest and a service worker.
  void OnHasServiceWorker(content::WebContents* web_contents);

  // Returns whether the given web app has already been installed.
  // Implemented on desktop platforms only.
  virtual bool IsWebAppInstalled(content::BrowserContext* browser_context,
                                 const GURL& start_url);

  // Record that the banner could be shown at this point, if the triggering
  // heuristic allowed.
  void RecordCouldShowBanner();

  // Creates a banner for the app using the given |icon|.
  virtual void ShowBanner(const SkBitmap* icon,
                          const base::string16& title,
                          const std::string& referrer) = 0;

  // Returns whether the banner should be shown.
  bool CheckIfShouldShowBanner();

  // Returns whether the fetcher is active and web contents have not been
  // closed.
  bool CheckFetcherIsStillAlive(content::WebContents* web_contents);

  // Returns whether the given Manifest is following the requirements to show
  // a web app banner.
  static bool IsManifestValidForWebApp(const content::Manifest& manifest,
                                       content::WebContents* web_contents,
                                       bool is_debug_mode);

  const base::WeakPtr<Delegate> weak_delegate_;
  const int ideal_icon_size_in_dp_;
  const int minimum_icon_size_in_dp_;
  base::ObserverList<Observer> observer_list_;
  bool is_active_;
  bool was_canceled_by_page_;
  bool page_requested_prompt_;
  const bool is_debug_mode_;
  ui::PageTransition transition_type_;
  int event_request_id_;
  scoped_ptr<SkBitmap> app_icon_;
  std::string referrer_;

  GURL validated_url_;
  base::string16 app_title_;
  content::Manifest web_app_data_;

  friend struct content::BrowserThread::DeleteOnThread<
      content::BrowserThread::UI>;
  friend class base::DeleteHelper<AppBannerDataFetcher>;
  friend class AppBannerDataFetcherUnitTest;
  friend class base::RefCounted<AppBannerDataFetcher>;
  DISALLOW_COPY_AND_ASSIGN(AppBannerDataFetcher);
};

}  // namespace banners

#endif  // CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_H_