Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2954)

Unified Diff: chrome/browser/chromeos/first_run/drive_first_run_controller.cc

Issue 55423004: Enable Google Drive offline mode automatically on first run. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Renamed to DriveFirstRunController Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/first_run/drive_first_run_controller.cc
diff --git a/chrome/browser/chromeos/first_run/drive_first_run_controller.cc b/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
new file mode 100644
index 0000000000000000000000000000000000000000..55772efa8c7fa56451253351959e7166f7a5cfda
--- /dev/null
+++ b/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
@@ -0,0 +1,325 @@
+// 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_first_run_controller.h"
+
+#include "base/callback.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 kDriveOfflineEndpointUrl[] = "http://drive.google.com";
+
+// Google Drive app id.
+const char kDriveHostedAppId[] = "apdfllckaahabafndbhieahigkjlhalf";
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// DriveWebContentsManager
+
+// 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 sync the user's
+// files for offline use.
+class DriveWebContentsManager : public content::WebContentsObserver,
+ public content::WebContentsDelegate,
+ public content::NotificationObserver {
+ public:
+ typedef base::Callback<void(bool)> DoneCallback;
achuithb 2013/11/04 20:33:24 CompletionCallback?
Tim Song 2013/11/05 01:18:06 Done.
+
+ DriveWebContentsManager(Profile* profile,
+ DriveFirstRunController* controller,
+ DoneCallback done_callback);
+ virtual ~DriveWebContentsManager();
+
+ void StartLoad();
achuithb 2013/11/04 20:33:24 Please add a function commment for all the functio
Tim Song 2013/11/05 01:18:06 Done.
+ void StopLoad();
+
+ private:
+ void OnOptInDone(bool success);
+ void DispatchResultToController(bool success);
+
+ // 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) OVERRIDE;
+
+ // 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_;
+ DriveFirstRunController* controller_;
+ scoped_ptr<content::WebContents> web_contents_;
+ content::NotificationRegistrar registrar_;
+ bool started_;
+ DoneCallback done_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriveWebContentsManager);
+};
+
+DriveWebContentsManager::DriveWebContentsManager(
+ Profile* profile,
+ DriveFirstRunController* controller,
+ DoneCallback done_callback)
+ : profile_(profile),
+ controller_(controller),
+ started_(false),
+ done_callback_(done_callback) {
+ registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED,
achuithb 2013/11/04 20:33:24 Maybe assert that done_callback is not null?
Tim Song 2013/11/05 01:18:06 Done.
+ content::Source<Profile>(profile_));
+}
+
+DriveWebContentsManager::~DriveWebContentsManager() {
+}
+
+void DriveWebContentsManager::StartLoad() {
+ started_ = true;
+ const GURL url(kDriveOfflineEndpointUrl);
+ 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 DriveWebContentsManager::StopLoad() {
+ started_ = false;
+}
+
+void DriveWebContentsManager::OnOptInDone(bool success) {
+ if (started_) {
+ base::MessageLoop::current()->PostTask(
achuithb 2013/11/04 20:33:24 Why do we post instead of running the callback dir
Tim Song 2013/11/05 01:18:06 Done.
+ FROM_HERE,
+ base::Bind(&DriveWebContentsManager::DispatchResultToController,
+ base::Unretained(this),
achuithb 2013/11/04 20:33:24 Is this safe (using base::Unretained)? If so, can
Tim Song 2013/11/05 01:18:06 Done. Replaced with WeakPtr.
+ success));
+ StopLoad();
+ }
+}
+
+void DriveWebContentsManager::DispatchResultToController(bool success) {
+ done_callback_.Run(success);
+}
+
+void DriveWebContentsManager::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) {
+ OnOptInDone(false);
+}
+
+void DriveWebContentsManager::DidFailLoad(
+ int64 frame_id,
+ const GURL& validated_url,
+ bool is_main_frame,
+ int error_code,
+ const string16& error_description,
+ content::RenderViewHost* render_view_host) {
+ OnOptInDone(false);
+}
+
+bool DriveWebContentsManager::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) {
+
+ 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;
+}
+
+void DriveWebContentsManager::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED) {
+ const std::string app_id = UTF16ToUTF8(
+ content::Details<BackgroundContentsOpenedDetails>(details)
+ ->application_id);
+ if (app_id == kDriveHostedAppId)
+ OnOptInDone(true);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DriveFirstRunController
+
+DriveFirstRunController::DriveFirstRunController()
+ : profile_(ProfileManager::GetDefaultProfile()),
+ started_(false) {
+}
+
+DriveFirstRunController::~DriveFirstRunController() {
+}
+
+void DriveFirstRunController::EnableOfflineMode() {
+ if (!started_) {
+ started_ = true;
+ initial_delay_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromSeconds(kInitialDelaySeconds),
+ this,
+ &DriveFirstRunController::EnableOfflineMode);
+ }
+
+ if (!UserManager::Get()->IsLoggedInAsRegularUser()) {
+ LOG(ERROR) << "Attempting to opt-in but not logged in a regular user.";
achuithb 2013/11/04 20:33:24 Attempting to enable offline access to drive but n
Tim Song 2013/11/05 01:18:06 Done.
+ OnOptInDone(false);
+ return;
+ }
+
+ ExtensionService* extension_service =
+ extensions::ExtensionSystem::Get(profile_)->extension_service();
+ if (!extension_service->GetExtensionById(kDriveHostedAppId, false)) {
+ LOG(WARNING) << "Drive app not is not installed.";
achuithb 2013/11/04 20:33:24 unnecessary "not"
Tim Song 2013/11/05 01:18:06 Done.
+ OnOptInDone(false);
+ return;
+ }
+
+ BackgroundContentsService* background_contents_service =
+ BackgroundContentsServiceFactory::GetForProfile(profile_);
+ if (background_contents_service->GetAppBackgroundContents(
+ UTF8ToUTF16(kDriveHostedAppId))) {
+ LOG(WARNING) << "Background page for Drive app already exists";
+ OnOptInDone(false);
+ return;
+ }
+
+ web_contents_manager_.reset(new DriveWebContentsManager(
+ profile_,
+ this,
+ base::Bind(&DriveFirstRunController::OnOptInDone,
+ base::Unretained(this))));
+ web_contents_manager_->StartLoad();
+ web_contents_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromSeconds(kWebContentsTimeoutSeconds),
+ this,
+ &DriveFirstRunController::OnWebContentsTimedOut);
+}
+
+void DriveFirstRunController::OnWebContentsTimedOut() {
+ LOG(WARNING) << "Timed out waiting for web contents to opt-in";
+ OnOptInDone(false);
+}
+
+void DriveFirstRunController::CleanUp() {
+ if (web_contents_manager_)
+ web_contents_manager_->StopLoad();
+ web_contents_timer_.Stop();
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void DriveFirstRunController::OnOptInDone(bool success) {
+ 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();
+}
+
+} // namespace chromeos

Powered by Google App Engine
This is Rietveld 408576698