Index: chrome/browser/chromeos/first_run/drive_opt_in_controller.cc |
diff --git a/chrome/browser/chromeos/first_run/drive_opt_in_controller.cc b/chrome/browser/chromeos/first_run/drive_opt_in_controller.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..30b290692f065950a6c65ae91a48c70dc4f5a85d |
--- /dev/null |
+++ b/chrome/browser/chromeos/first_run/drive_opt_in_controller.cc |
@@ -0,0 +1,327 @@ |
+// Copyright 2013 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. |
+ |
+#include "chrome/browser/chromeos/first_run/drive_opt_in_controller.h" |
+ |
+#include "base/message_loop/message_loop.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "chrome/browser/background/background_contents_service.h" |
+#include "chrome/browser/background/background_contents_service_factory.h" |
+#include "chrome/browser/chrome_notification_types.h" |
+#include "chrome/browser/chromeos/login/user_manager.h" |
+#include "chrome/browser/extensions/extension_service.h" |
+#include "chrome/browser/extensions/extension_system.h" |
+#include "chrome/browser/profiles/profile_manager.h" |
+#include "chrome/browser/tab_contents/background_contents.h" |
+#include "chrome/common/extensions/extension.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/navigation_controller.h" |
+#include "content/public/browser/notification_details.h" |
+#include "content/public/browser/notification_observer.h" |
+#include "content/public/browser/notification_registrar.h" |
+#include "content/public/browser/notification_source.h" |
+#include "content/public/browser/notification_types.h" |
+#include "content/public/browser/site_instance.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/browser/web_contents_observer.h" |
+#include "url/gurl.h" |
+ |
+namespace chromeos { |
+ |
+namespace { |
+ |
+// The initial time to wait in seconds before starting the opt-in. |
+const int kInitialDelaySeconds = 180; |
+ |
+// Time to wait for Drive app background page to come up before giving up. |
+const int kWebContentsTimeoutSeconds = 15; |
+ |
+// Google Drive offline opt-in endpoint. |
+const char kDriveOfflineOptInUrl[] = "http://drive.google.com"; |
+ |
+// Google Drive app id. |
+const char kDriveHostedAppId[] = "apdfllckaahabafndbhieahigkjlhalf"; |
+ |
+} // namespace |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// DriveOptInWebContentsManager |
+ |
+// Manages web contents that does Google Drive offline opt-in. We create |
+// a background WebContents that loads a Drive endpoint to initialize offline |
+// mode. If successful, a background page will be opened to do sync the user's |
achuithb
2013/11/01 19:25:15
"do" unnecessary
Tim Song
2013/11/02 00:13:14
Done.
|
+// files for offline use. |
+class DriveOptInWebContentsManager : public content::WebContentsObserver, |
+ public content::WebContentsDelegate, |
+ public content::NotificationObserver { |
+ public: |
+ DriveOptInWebContentsManager(Profile* profile, |
+ DriveOptInController* controller); |
+ ~DriveOptInWebContentsManager(); |
achuithb
2013/11/01 19:25:15
virtual
Tim Song
2013/11/02 00:13:14
Done.
|
+ |
+ void StartLoad(); |
+ void StopLoad(); |
+ |
+ private: |
+ void OnOptInSuccess(); |
+ void OnOptInFailure(); |
+ |
+ // content::WebContentsObserver overrides: |
+ virtual void DidFailProvisionalLoad( |
+ int64 frame_id, |
+ const string16& frame_unique_name, |
+ bool is_main_frame, |
+ const GURL& validated_url, |
+ int error_code, |
+ const string16& error_description, |
+ content::RenderViewHost* render_view_host) OVERRIDE; |
+ |
+ virtual void DidFailLoad(int64 frame_id, |
+ const GURL& validated_url, |
+ bool is_main_frame, |
+ int error_code, |
+ const string16& error_description, |
+ content::RenderViewHost* render_view_host); |
achuithb
2013/11/01 19:25:15
OVERRIDE
Tim Song
2013/11/02 00:13:14
Done.
|
+ |
+ // content::WebContentsDelegate overrides: |
+ virtual bool ShouldCreateWebContents( |
+ content::WebContents* web_contents, |
+ int route_id, |
+ WindowContainerType window_container_type, |
+ const string16& frame_name, |
+ const GURL& target_url, |
+ const std::string& partition_id, |
+ content::SessionStorageNamespace* session_storage_namespace) OVERRIDE; |
+ |
+ // content::NotificationObserver overrides: |
+ virtual void Observe(int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) OVERRIDE; |
+ |
+ Profile* profile_; |
+ DriveOptInController* controller_; |
+ scoped_ptr<content::WebContents> web_contents_; |
+ content::NotificationRegistrar registrar_; |
+ bool started_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DriveOptInWebContentsManager); |
+}; |
+ |
+DriveOptInWebContentsManager::DriveOptInWebContentsManager( |
+ Profile* profile, DriveOptInController* controller) |
+ : profile_(profile), |
+ controller_(controller), |
+ started_(false) { |
+ registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, |
+ content::Source<Profile>(profile_)); |
+} |
+ |
+DriveOptInWebContentsManager::~DriveOptInWebContentsManager() { |
+} |
+ |
+void DriveOptInWebContentsManager::StartLoad() { |
+ started_ = true; |
+ GURL url(kDriveOfflineOptInUrl); |
achuithb
2013/11/01 19:25:15
const?
Tim Song
2013/11/02 00:13:14
Done.
|
+ content::WebContents::CreateParams create_params( |
+ profile_, content::SiteInstance::CreateForURL(profile_, url)); |
+ |
+ web_contents_.reset(content::WebContents::Create(create_params)); |
+ web_contents_->SetDelegate(this); |
+ |
+ content::NavigationController::LoadURLParams load_params(url); |
+ load_params.transition_type = content::PAGE_TRANSITION_GENERATED; |
+ web_contents_->GetController().LoadURLWithParams(load_params); |
+ |
+ content::WebContentsObserver::Observe(web_contents_.get()); |
+} |
+ |
+void DriveOptInWebContentsManager::StopLoad() { |
+ started_ = false; |
+} |
+ |
+void DriveOptInWebContentsManager::OnOptInSuccess() { |
+ if (started_) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DriveOptInController::OnOptInSuccess, |
+ base::Unretained(controller_))); |
+ StopLoad(); |
+ } |
+} |
+ |
+void DriveOptInWebContentsManager::OnOptInFailure() { |
+ if (started_) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DriveOptInController::OnOptInFailure, |
+ base::Unretained(controller_))); |
+ StopLoad(); |
+ } |
+} |
+ |
+void DriveOptInWebContentsManager::DidFailProvisionalLoad( |
+ int64 frame_id, |
+ const string16& frame_unique_name, |
+ bool is_main_frame, |
+ const GURL& validated_url, |
+ int error_code, |
+ const string16& error_description, |
+ content::RenderViewHost* render_view_host) { |
+ OnOptInFailure(); |
+} |
+ |
+void DriveOptInWebContentsManager::DidFailLoad( |
+ int64 frame_id, |
+ const GURL& validated_url, |
+ bool is_main_frame, |
+ int error_code, |
+ const string16& error_description, |
+ content::RenderViewHost* render_view_host) OVERRIDE { |
+ OnOptInFailure(); |
+} |
+ |
+// content::WebContentsDelegate overrides: |
achuithb
2013/11/01 19:25:15
don't think you need this
Tim Song
2013/11/02 00:13:14
Done.
|
+bool DriveOptInWebContentsManager::ShouldCreateWebContents( |
+ content::WebContents* web_contents, |
+ int route_id, |
+ WindowContainerType window_container_type, |
+ const string16& frame_name, |
+ const GURL& target_url, |
+ const std::string& partition_id, |
+ content::SessionStorageNamespace* session_storage_namespace) OVERRIDE { |
achuithb
2013/11/01 19:25:15
don't think you need OVERRIDE here
Tim Song
2013/11/02 00:13:14
Done.
|
+ |
+ if (window_container_type == WINDOW_CONTAINER_TYPE_NORMAL) |
+ return true; |
+ |
+ // Check that the target URL is for the Drive app. |
+ ExtensionService* service = |
+ extensions::ExtensionSystem::Get(profile_)->extension_service(); |
+ const extensions::Extension *extension = |
+ service->GetInstalledApp(target_url); |
+ if (!extension || extension->id() != kDriveHostedAppId) |
+ return true; |
+ |
+ // The background contents creation is normally done in Browser, but |
+ // because we're using a detached WebContents, we need to do it ourselves. |
+ BackgroundContentsService* background_contents_service = |
+ BackgroundContentsServiceFactory::GetForProfile(profile_); |
+ |
+ // Prevent redirection if background contents already exists. |
+ if (background_contents_service->GetAppBackgroundContents( |
+ UTF8ToUTF16(kDriveHostedAppId))) { |
+ return false; |
+ } |
+ BackgroundContents* contents = background_contents_service |
+ ->CreateBackgroundContents(content::SiteInstance::Create(profile_), |
+ route_id, |
+ profile_, |
+ frame_name, |
+ ASCIIToUTF16(kDriveHostedAppId), |
+ partition_id, |
+ session_storage_namespace); |
+ |
+ contents->web_contents()->GetController().LoadURL( |
+ target_url, |
+ content::Referrer(), |
+ content::PAGE_TRANSITION_LINK, |
+ std::string()); |
+ |
+ // Return false as we already created the WebContents here. |
+ return false; |
+} |
+ |
+// content::NotificationObserver overrides: |
achuithb
2013/11/01 19:25:15
don't think you need this
Tim Song
2013/11/02 00:13:14
Done.
|
+void DriveOptInWebContentsManager::Observe( |
+ int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) OVERRIDE { |
+ if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED) { |
+ std::string app_id = UTF16ToUTF8( |
achuithb
2013/11/01 19:25:15
const?
Tim Song
2013/11/02 00:13:14
Done.
|
+ content::Details<BackgroundContentsOpenedDetails>(details) |
+ ->application_id); |
+ if (app_id == kDriveHostedAppId) { |
achuithb
2013/11/01 19:25:15
don't need {}
Tim Song
2013/11/02 00:13:14
Done.
|
+ OnOptInSuccess(); |
+ } |
+ } |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// DriveOptInController |
+ |
+DriveOptInController::DriveOptInController() |
+ : profile_(ProfileManager::GetDefaultProfile()), |
+ initial_delay_done_(false) { |
+} |
+ |
+DriveOptInController::~DriveOptInController() { |
+} |
+ |
+void DriveOptInController::StartOfflineOptIn() { |
+ if (!initial_delay_done_) { |
+ initial_delay_done_ = true; |
+ initial_delay_timer_.Start( |
+ FROM_HERE, |
+ base::TimeDelta::FromSeconds(kInitialDelaySeconds), |
+ this, |
+ &DriveOptInController::StartOfflineOptIn); |
+ } |
+ |
+ if (!UserManager::Get()->IsLoggedInAsRegularUser()) { |
+ LOG(ERROR) << "Attempting to opt-in but not logged in a regular user."; |
+ OnOptInFailure(); |
+ return; |
+ } |
+ |
+ ExtensionService* extension_service = |
+ extensions::ExtensionSystem::Get(profile_)->extension_service(); |
+ if (!extension_service->GetExtensionById(kDriveHostedAppId, false)) { |
+ LOG(WARNING) << "Drive app not is not installed."; |
+ OnOptInFailure(); |
+ return; |
+ } |
+ |
+ BackgroundContentsService* background_contents_service = |
+ BackgroundContentsServiceFactory::GetForProfile(profile_); |
+ if (background_contents_service->GetAppBackgroundContents( |
+ UTF8ToUTF16(kDriveHostedAppId))) { |
+ LOG(WARNING) << "Background page for Drive app already exists"; |
+ OnOptInFailure(); |
+ return; |
+ } |
+ |
+ web_contents_manager_.reset( |
+ new DriveOptInWebContentsManager(profile_, this)); |
+ web_contents_manager_->StartLoad(); |
+ web_contents_timer_.Start( |
+ FROM_HERE, |
+ base::TimeDelta::FromSeconds(kWebContentsTimeoutSeconds), |
+ this, |
+ &DriveOptInController::OnWebContentsTimedOut); |
+} |
+ |
+void DriveOptInController::OnWebContentsTimedOut() { |
+ LOG(WARNING) << "Timed out waiting for web contents to opt-in"; |
+ OnOptInFailure(); |
+} |
+ |
+void DriveOptInController::CleanUp() { |
+ if (web_contents_manager_) |
+ web_contents_manager_->StopLoad(); |
+ web_contents_timer_.Stop(); |
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
+} |
+ |
+void DriveOptInController::OnOptInSuccess() { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ // TODO(tengs): Notify ash system tray to display notice that Drive |
+ // offline opt-in has occurred. See crbug.com/311452. |
+ CleanUp(); |
+} |
+ |
+void DriveOptInController::OnOptInFailure() { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ CleanUp(); |
+} |
+ |
+} // namespace chromeos |