1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file.
4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/chromeos/first_run/drive_first_run_controller.h"
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shell.h"
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/system/tray/system_tray_delegate.h"
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/callback.h"
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/weak_ptr.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/message_loop/message_loop.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/background/background_contents_service.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/background/background_contents_service_factory.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/tab_contents/background_contents.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/browser_navigator.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/singleton_tabs.h"
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/grit/generated_resources.h"
256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/grit/theme_resources.h"
266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/user_manager/user_manager.h"
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/navigation_controller.h"
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/notification_details.h"
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/notification_observer.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/notification_registrar.h"
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/notification_source.h"
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/notification_types.h"
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/browser/render_frame_host.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/site_instance.h"
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/web_contents.h"
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/web_contents_observer.h"
38a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/browser/extension_registry.h"
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
41a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/extension_set.h"
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/message_center/message_center.h"
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/message_center/notification.h"
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/message_center/notification_delegate.h"
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "url/gurl.h"
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace chromeos {
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The initial time to wait in seconds before enabling offline mode.
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int kInitialDelaySeconds = 180;
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Time to wait for Drive app background page to come up before giving up.
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int kWebContentsTimeoutSeconds = 15;
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Google Drive enable offline endpoint.
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDriveOfflineEndpointUrl[] =
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "https://docs.google.com/offline/autoenable";
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Google Drive app id.
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const char kDriveHostedAppId[] = "apdfllckaahabafndbhieahigkjlhalf";
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Id of the notification shown when offline mode is enabled.
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const char kDriveOfflineNotificationId[] = "chrome://drive/enable-offline";
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The URL of the support page opened when the notification button is clicked.
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDriveOfflineSupportUrl[] =
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "https://support.google.com/drive/answer/1628467";
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// DriveOfflineNotificationDelegate
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// NotificationDelegate for the notification that is displayed when Drive
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// offline mode is enabled automatically. Clicking on the notification button
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// will open the Drive settings page.
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class DriveOfflineNotificationDelegate
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : public message_center::NotificationDelegate {
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit DriveOfflineNotificationDelegate(Profile* profile)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : profile_(profile) {}
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // message_center::NotificationDelegate overrides:
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void Display() OVERRIDE {}
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void Error() OVERRIDE {}
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void Close(bool by_user) OVERRIDE {}
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void Click() OVERRIDE {}
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void ButtonClick(int button_index) OVERRIDE;
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) protected:
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual ~DriveOfflineNotificationDelegate() {}
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile_;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DriveOfflineNotificationDelegate);
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void DriveOfflineNotificationDelegate::ButtonClick(int button_index) {
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK_EQ(0, button_index);
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The support page will be localized based on the user's GAIA account.
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const GURL url = GURL(kDriveOfflineSupportUrl);
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  chrome::ScopedTabbedBrowserDisplayer displayer(
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       profile_,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       chrome::HOST_DESKTOP_TYPE_ASH);
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  chrome::ShowSingletonTabOverwritingNTP(
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      displayer.browser(),
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      chrome::GetSingletonTabNavigateParams(displayer.browser(), url));
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// DriveWebContentsManager
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Manages web contents that initializes Google Drive offline mode. We create
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// a background WebContents that loads a Drive endpoint to initialize offline
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// mode. If successful, a background page will be opened to sync the user's
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// files for offline use.
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class DriveWebContentsManager : public content::WebContentsObserver,
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                public content::WebContentsDelegate,
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                public content::NotificationObserver {
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public:
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  typedef base::Callback<
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      void(bool, DriveFirstRunController::UMAOutcome)> CompletionCallback;
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DriveWebContentsManager(Profile* profile,
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          const std::string& app_id,
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          const std::string& endpoint_url,
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          const CompletionCallback& completion_callback);
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual ~DriveWebContentsManager();
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Start loading the WebContents for the endpoint in the context of the Drive
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // hosted app that will initialize offline mode and open a background page.
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void StartLoad();
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Stop loading the endpoint. The |completion_callback| will not be called.
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void StopLoad();
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private:
145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Called when when offline initialization succeeds or fails and schedules
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // |RunCompletionCallback|.
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnOfflineInit(bool success,
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     DriveFirstRunController::UMAOutcome outcome);
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Runs |completion_callback|.
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RunCompletionCallback(bool success,
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             DriveFirstRunController::UMAOutcome outcome);
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // content::WebContentsObserver overrides:
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void DidFailProvisionalLoad(
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      content::RenderFrameHost* render_frame_host,
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const GURL& validated_url,
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      int error_code,
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      const base::string16& error_description) OVERRIDE;
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void DidFailLoad(content::RenderFrameHost* render_frame_host,
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           const GURL& validated_url,
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           int error_code,
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           const base::string16& error_description) OVERRIDE;
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // content::WebContentsDelegate overrides:
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual bool ShouldCreateWebContents(
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      content::WebContents* web_contents,
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      int route_id,
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      WindowContainerType window_container_type,
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const base::string16& frame_name,
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const GURL& target_url,
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const std::string& partition_id,
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      content::SessionStorageNamespace* session_storage_namespace) OVERRIDE;
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // content::NotificationObserver overrides:
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void Observe(int type,
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                       const content::NotificationSource& source,
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                       const content::NotificationDetails& details) OVERRIDE;
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Profile* profile_;
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const std::string app_id_;
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const std::string endpoint_url_;
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<content::WebContents> web_contents_;
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  content::NotificationRegistrar registrar_;
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool started_;
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CompletionCallback completion_callback_;
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::WeakPtrFactory<DriveWebContentsManager> weak_ptr_factory_;
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DriveWebContentsManager);
191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)DriveWebContentsManager::DriveWebContentsManager(
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Profile* profile,
195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& app_id,
196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& endpoint_url,
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const CompletionCallback& completion_callback)
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : profile_(profile),
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      app_id_(app_id),
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      endpoint_url_(endpoint_url),
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      started_(false),
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      completion_callback_(completion_callback),
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      weak_ptr_factory_(this) {
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!completion_callback_.is_null());
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED,
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 content::Source<Profile>(profile_));
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)DriveWebContentsManager::~DriveWebContentsManager() {
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveWebContentsManager::StartLoad() {
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  started_ = true;
214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const GURL url(endpoint_url_);
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  content::WebContents::CreateParams create_params(
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        profile_, content::SiteInstance::CreateForURL(profile_, url));
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_contents_.reset(content::WebContents::Create(create_params));
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_contents_->SetDelegate(this);
22023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      web_contents_.get());
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  content::NavigationController::LoadURLParams load_params(url);
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_contents_->GetController().LoadURLWithParams(load_params);
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  content::WebContentsObserver::Observe(web_contents_.get());
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveWebContentsManager::StopLoad() {
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  started_ = false;
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DriveWebContentsManager::OnOfflineInit(
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success,
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DriveFirstRunController::UMAOutcome outcome) {
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (started_) {
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // We postpone notifying the controller as we may be in the middle
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // of a call stack for some routine of the contained WebContents.
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        FROM_HERE,
242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::Bind(&DriveWebContentsManager::RunCompletionCallback,
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   success,
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   outcome));
246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    StopLoad();
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DriveWebContentsManager::RunCompletionCallback(
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success,
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DriveFirstRunController::UMAOutcome outcome) {
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  completion_callback_.Run(success, outcome);
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveWebContentsManager::DidFailProvisionalLoad(
257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::RenderFrameHost* render_frame_host,
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const GURL& validated_url,
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int error_code,
260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::string16& error_description) {
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!render_frame_host->GetParent()) {
262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(WARNING) << "Failed to load WebContents to enable offline mode.";
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnOfflineInit(false,
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  DriveFirstRunController::OUTCOME_WEB_CONTENTS_LOAD_FAILED);
265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveWebContentsManager::DidFailLoad(
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::RenderFrameHost* render_frame_host,
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const GURL& validated_url,
271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int error_code,
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::string16& error_description) {
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!render_frame_host->GetParent()) {
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(WARNING) << "Failed to load WebContents to enable offline mode.";
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnOfflineInit(false,
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  DriveFirstRunController::OUTCOME_WEB_CONTENTS_LOAD_FAILED);
277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool DriveWebContentsManager::ShouldCreateWebContents(
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    content::WebContents* web_contents,
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int route_id,
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    WindowContainerType window_container_type,
284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& frame_name,
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const GURL& target_url,
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& partition_id,
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    content::SessionStorageNamespace* session_storage_namespace) {
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (window_container_type == WINDOW_CONTAINER_TYPE_NORMAL)
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Check that the target URL is for the Drive app.
293a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const extensions::Extension* extension =
294a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      extensions::ExtensionRegistry::Get(profile_)
295a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          ->enabled_extensions().GetAppByURL(target_url);
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!extension || extension->id() != app_id_)
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The background contents creation is normally done in Browser, but
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // because we're using a detached WebContents, we need to do it ourselves.
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BackgroundContentsService* background_contents_service =
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      BackgroundContentsServiceFactory::GetForProfile(profile_);
303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Prevent redirection if background contents already exists.
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (background_contents_service->GetAppBackgroundContents(
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::UTF8ToUTF16(app_id_))) {
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BackgroundContents* contents = background_contents_service
310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ->CreateBackgroundContents(content::SiteInstance::Create(profile_),
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 route_id,
312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 profile_,
313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 frame_name,
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 base::ASCIIToUTF16(app_id_),
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 partition_id,
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 session_storage_namespace);
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  contents->web_contents()->GetController().LoadURL(
319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      target_url,
320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      content::Referrer(),
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ui::PAGE_TRANSITION_LINK,
322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      std::string());
323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Return false as we already created the WebContents here.
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return false;
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveWebContentsManager::Observe(
329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int type,
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const content::NotificationSource& source,
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const content::NotificationDetails& details) {
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED) {
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string app_id = base::UTF16ToUTF8(
334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        content::Details<BackgroundContentsOpenedDetails>(details)
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            ->application_id);
336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (app_id == app_id_)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnOfflineInit(true, DriveFirstRunController::OUTCOME_OFFLINE_ENABLED);
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// DriveFirstRunController
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DriveFirstRunController::DriveFirstRunController(Profile* profile)
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : profile_(profile),
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      started_(false),
347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      initial_delay_secs_(kInitialDelaySeconds),
348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      web_contents_timeout_secs_(kWebContentsTimeoutSeconds),
349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      drive_offline_endpoint_url_(kDriveOfflineEndpointUrl),
350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      drive_hosted_app_id_(kDriveHostedAppId) {
351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)DriveFirstRunController::~DriveFirstRunController() {
354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveFirstRunController::EnableOfflineMode() {
357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!started_) {
358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    started_ = true;
359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    initial_delay_timer_.Start(
360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE,
361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::TimeDelta::FromSeconds(initial_delay_secs_),
362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      this,
363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      &DriveFirstRunController::EnableOfflineMode);
364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!user_manager::UserManager::Get()->IsLoggedInAsRegularUser()) {
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(ERROR) << "Attempting to enable offline access "
369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                  "but not logged in a regular user.";
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnOfflineInit(false, OUTCOME_WRONG_USER_TYPE);
371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionService* extension_service =
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->extension_service();
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!extension_service->GetExtensionById(drive_hosted_app_id_, false)) {
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(WARNING) << "Drive app is not installed.";
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnOfflineInit(false, OUTCOME_APP_NOT_INSTALLED);
379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BackgroundContentsService* background_contents_service =
383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      BackgroundContentsServiceFactory::GetForProfile(profile_);
384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (background_contents_service->GetAppBackgroundContents(
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::UTF8ToUTF16(drive_hosted_app_id_))) {
386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(WARNING) << "Background page for Drive app already exists";
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnOfflineInit(false, OUTCOME_BACKGROUND_PAGE_EXISTS);
388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_contents_manager_.reset(new DriveWebContentsManager(
392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      profile_,
393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      drive_hosted_app_id_,
394f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      drive_offline_endpoint_url_,
395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(&DriveFirstRunController::OnOfflineInit,
396f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 base::Unretained(this))));
397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_contents_manager_->StartLoad();
398f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_contents_timer_.Start(
399f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE,
400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::TimeDelta::FromSeconds(web_contents_timeout_secs_),
401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      this,
402f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      &DriveFirstRunController::OnWebContentsTimedOut);
403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
404f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
405f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveFirstRunController::AddObserver(Observer* observer) {
406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  observer_list_.AddObserver(observer);
407f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
408f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveFirstRunController::RemoveObserver(Observer* observer) {
410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  observer_list_.RemoveObserver(observer);
411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveFirstRunController::SetDelaysForTest(int initial_delay_secs,
414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                               int timeout_secs) {
415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!started_);
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  initial_delay_secs_ = initial_delay_secs;
417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_contents_timeout_secs_ = timeout_secs;
418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
419f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveFirstRunController::SetAppInfoForTest(
421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& app_id,
422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& endpoint_url) {
423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!started_);
424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  drive_hosted_app_id_ = app_id;
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  drive_offline_endpoint_url_ = endpoint_url;
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveFirstRunController::OnWebContentsTimedOut() {
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOG(WARNING) << "Timed out waiting for web contents.";
430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observer_list_, OnTimedOut());
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  OnOfflineInit(false, OUTCOME_WEB_CONTENTS_TIMED_OUT);
432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DriveFirstRunController::CleanUp() {
435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (web_contents_manager_)
436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    web_contents_manager_->StopLoad();
437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_contents_timer_.Stop();
438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
440f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DriveFirstRunController::OnOfflineInit(bool success, UMAOutcome outcome) {
442f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
443a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (success)
444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ShowNotification();
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("DriveOffline.CrosAutoEnableOutcome",
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            outcome, OUTCOME_MAX);
447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observer_list_, OnCompletion(success));
448f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CleanUp();
449f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
450f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void DriveFirstRunController::ShowNotification() {
452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ExtensionService* service =
453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->extension_service();
454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(service);
455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const extensions::Extension* extension =
456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      service->GetExtensionById(drive_hosted_app_id_, false);
457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(extension);
458a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
459a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  message_center::RichNotificationData data;
460a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  data.buttons.push_back(message_center::ButtonInfo(
461a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_DRIVE_OFFLINE_NOTIFICATION_BUTTON)));
462a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
463a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<message_center::Notification> notification(
464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new message_center::Notification(
465a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          message_center::NOTIFICATION_TYPE_SIMPLE,
466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          kDriveOfflineNotificationId,
467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          base::string16(), // title
468a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          l10n_util::GetStringUTF16(IDS_DRIVE_OFFLINE_NOTIFICATION_MESSAGE),
469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          resource_bundle.GetImageNamed(IDR_NOTIFICATION_DRIVE),
470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          base::UTF8ToUTF16(extension->name()),
471a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          message_center::NotifierId(message_center::NotifierId::APPLICATION,
472a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     kDriveHostedAppId),
473a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          data,
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new DriveOfflineNotificationDelegate(profile_)));
475a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  notification->set_priority(message_center::LOW_PRIORITY);
476a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
478a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace chromeos
480