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

Side by Side 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: Fixes 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h"
6
7 #include "base/callback.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/background/background_contents_service.h"
12 #include "chrome/browser/background/background_contents_service_factory.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/chromeos/login/user_manager.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_system.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/tab_contents/background_contents.h"
19 #include "chrome/common/extensions/extension.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/navigation_controller.h"
22 #include "content/public/browser/notification_details.h"
23 #include "content/public/browser/notification_observer.h"
24 #include "content/public/browser/notification_registrar.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/notification_types.h"
27 #include "content/public/browser/site_instance.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/browser/web_contents_observer.h"
30 #include "url/gurl.h"
31
32 namespace chromeos {
33
34 namespace {
35
36 // The initial time to wait in seconds before starting the opt-in.
37 const int kInitialDelaySeconds = 180;
38
39 // Time to wait for Drive app background page to come up before giving up.
40 const int kWebContentsTimeoutSeconds = 15;
41
42 // Google Drive offline opt-in endpoint.
43 const char kDriveOfflineEndpointUrl[] = "http://drive.google.com";
44
45 // Google Drive app id.
46 const char kDriveHostedAppId[] = "apdfllckaahabafndbhieahigkjlhalf";
47
48 } // namespace
49
50 ////////////////////////////////////////////////////////////////////////////////
51 // DriveWebContentsManager
52
53 // Manages web contents that does Google Drive offline opt-in. We create
54 // a background WebContents that loads a Drive endpoint to initialize offline
55 // mode. If successful, a background page will be opened to sync the user's
56 // files for offline use.
57 class DriveWebContentsManager : public content::WebContentsObserver,
58 public content::WebContentsDelegate,
59 public content::NotificationObserver {
60 public:
61 typedef base::Callback<void(bool)> CompletionCallback;
62
63 DriveWebContentsManager(Profile* profile,
64 CompletionCallback completion_callback);
achuithb 2013/11/05 01:30:47 const CompletionCallback&
Tim Song 2013/11/05 01:49:51 Done.
65 virtual ~DriveWebContentsManager();
66
67 // Start loading the WebContents for the endpoint in the context of the Drive
68 // hosted app that will initialize offline mode and open a background page.
69 void StartLoad();
70
71 // Stop loading the endpoint. The |completion_callback| will not be called.
72 void StopLoad();
73
74 private:
75 // Called when when the WebContents load succeeds or fails and schedules
76 // |RunCompletionCallback|.
77 void OnOptInDone(bool success);
achuithb 2013/11/05 01:30:47 OnWebContentsLoaded?
Tim Song 2013/11/05 01:49:51 Ah sorry, that comment is a bit inaccurate. Rename
78
79 // Runs |completion_callback|.
80 void RunCompletionCallback(bool success);
81
82 // content::WebContentsObserver overrides:
83 virtual void DidFailProvisionalLoad(
84 int64 frame_id,
85 const string16& frame_unique_name,
86 bool is_main_frame,
87 const GURL& validated_url,
88 int error_code,
89 const string16& error_description,
90 content::RenderViewHost* render_view_host) OVERRIDE;
91
92 virtual void DidFailLoad(int64 frame_id,
93 const GURL& validated_url,
94 bool is_main_frame,
95 int error_code,
96 const string16& error_description,
97 content::RenderViewHost* render_view_host) OVERRIDE;
98
99 // content::WebContentsDelegate overrides:
100 virtual bool ShouldCreateWebContents(
101 content::WebContents* web_contents,
102 int route_id,
103 WindowContainerType window_container_type,
104 const string16& frame_name,
105 const GURL& target_url,
106 const std::string& partition_id,
107 content::SessionStorageNamespace* session_storage_namespace) OVERRIDE;
108
109 // content::NotificationObserver overrides:
110 virtual void Observe(int type,
111 const content::NotificationSource& source,
112 const content::NotificationDetails& details) OVERRIDE;
113
114 Profile* profile_;
115 scoped_ptr<content::WebContents> web_contents_;
116 content::NotificationRegistrar registrar_;
117 bool started_;
118 CompletionCallback completion_callback_;
119 base::WeakPtrFactory<DriveWebContentsManager> weak_ptr_factory_;
120
121 DISALLOW_COPY_AND_ASSIGN(DriveWebContentsManager);
122 };
123
124 DriveWebContentsManager::DriveWebContentsManager(
125 Profile* profile,
126 CompletionCallback completion_callback)
127 : profile_(profile),
128 started_(false),
129 completion_callback_(completion_callback),
130 weak_ptr_factory_(this) {
131 DCHECK(!completion_callback_.is_null());
132 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED,
133 content::Source<Profile>(profile_));
134 }
135
136 DriveWebContentsManager::~DriveWebContentsManager() {
137 }
138
139 void DriveWebContentsManager::StartLoad() {
140 started_ = true;
141 const GURL url(kDriveOfflineEndpointUrl);
142 content::WebContents::CreateParams create_params(
143 profile_, content::SiteInstance::CreateForURL(profile_, url));
144
145 web_contents_.reset(content::WebContents::Create(create_params));
146 web_contents_->SetDelegate(this);
147
148 content::NavigationController::LoadURLParams load_params(url);
149 load_params.transition_type = content::PAGE_TRANSITION_GENERATED;
150 web_contents_->GetController().LoadURLWithParams(load_params);
151
152 content::WebContentsObserver::Observe(web_contents_.get());
153 }
154
155 void DriveWebContentsManager::StopLoad() {
156 started_ = false;
157 }
158
159 void DriveWebContentsManager::OnOptInDone(bool success) {
160 if (started_) {
161 // We postpone notifying the controller as we may be in the middle
162 // of a call stack for some routine of the contained WebContents.
163 base::MessageLoop::current()->PostTask(
164 FROM_HERE,
165 base::Bind(&DriveWebContentsManager::RunCompletionCallback,
166 weak_ptr_factory_.GetWeakPtr(),
167 success));
168 StopLoad();
169 }
170 }
171
172 void DriveWebContentsManager::RunCompletionCallback(bool success) {
173 completion_callback_.Run(success);
174 }
175
176 void DriveWebContentsManager::DidFailProvisionalLoad(
177 int64 frame_id,
178 const string16& frame_unique_name,
179 bool is_main_frame,
180 const GURL& validated_url,
181 int error_code,
182 const string16& error_description,
183 content::RenderViewHost* render_view_host) {
184 OnOptInDone(false);
185 }
186
187 void DriveWebContentsManager::DidFailLoad(
188 int64 frame_id,
189 const GURL& validated_url,
190 bool is_main_frame,
191 int error_code,
192 const string16& error_description,
193 content::RenderViewHost* render_view_host) {
194 OnOptInDone(false);
195 }
196
197 bool DriveWebContentsManager::ShouldCreateWebContents(
198 content::WebContents* web_contents,
199 int route_id,
200 WindowContainerType window_container_type,
201 const string16& frame_name,
202 const GURL& target_url,
203 const std::string& partition_id,
204 content::SessionStorageNamespace* session_storage_namespace) {
205
206 if (window_container_type == WINDOW_CONTAINER_TYPE_NORMAL)
207 return true;
208
209 // Check that the target URL is for the Drive app.
210 ExtensionService* service =
211 extensions::ExtensionSystem::Get(profile_)->extension_service();
212 const extensions::Extension *extension =
213 service->GetInstalledApp(target_url);
214 if (!extension || extension->id() != kDriveHostedAppId)
215 return true;
216
217 // The background contents creation is normally done in Browser, but
218 // because we're using a detached WebContents, we need to do it ourselves.
219 BackgroundContentsService* background_contents_service =
220 BackgroundContentsServiceFactory::GetForProfile(profile_);
221
222 // Prevent redirection if background contents already exists.
223 if (background_contents_service->GetAppBackgroundContents(
224 UTF8ToUTF16(kDriveHostedAppId))) {
225 return false;
226 }
227 BackgroundContents* contents = background_contents_service
228 ->CreateBackgroundContents(content::SiteInstance::Create(profile_),
229 route_id,
230 profile_,
231 frame_name,
232 ASCIIToUTF16(kDriveHostedAppId),
233 partition_id,
234 session_storage_namespace);
235
236 contents->web_contents()->GetController().LoadURL(
237 target_url,
238 content::Referrer(),
239 content::PAGE_TRANSITION_LINK,
240 std::string());
241
242 // Return false as we already created the WebContents here.
243 return false;
244 }
245
246 void DriveWebContentsManager::Observe(
247 int type,
248 const content::NotificationSource& source,
249 const content::NotificationDetails& details) {
250 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED) {
251 const std::string app_id = UTF16ToUTF8(
252 content::Details<BackgroundContentsOpenedDetails>(details)
253 ->application_id);
254 if (app_id == kDriveHostedAppId)
255 OnOptInDone(true);
256 }
257 }
258
259 ////////////////////////////////////////////////////////////////////////////////
260 // DriveFirstRunController
261
262 DriveFirstRunController::DriveFirstRunController()
263 : profile_(ProfileManager::GetDefaultProfile()),
264 started_(false) {
265 }
266
267 DriveFirstRunController::~DriveFirstRunController() {
268 }
269
270 void DriveFirstRunController::EnableOfflineMode() {
271 if (!started_) {
272 started_ = true;
273 initial_delay_timer_.Start(
274 FROM_HERE,
275 base::TimeDelta::FromSeconds(kInitialDelaySeconds),
276 this,
277 &DriveFirstRunController::EnableOfflineMode);
278 }
279
280 if (!UserManager::Get()->IsLoggedInAsRegularUser()) {
281 LOG(ERROR) << "Attempting to enable offline access "
282 "but not logged in a regular user.";
283 OnOptInDone(false);
284 return;
285 }
286
287 ExtensionService* extension_service =
288 extensions::ExtensionSystem::Get(profile_)->extension_service();
289 if (!extension_service->GetExtensionById(kDriveHostedAppId, false)) {
290 LOG(WARNING) << "Drive app is not installed.";
291 OnOptInDone(false);
292 return;
293 }
294
295 BackgroundContentsService* background_contents_service =
296 BackgroundContentsServiceFactory::GetForProfile(profile_);
297 if (background_contents_service->GetAppBackgroundContents(
298 UTF8ToUTF16(kDriveHostedAppId))) {
299 LOG(WARNING) << "Background page for Drive app already exists";
300 OnOptInDone(false);
301 return;
302 }
303
304 web_contents_manager_.reset(new DriveWebContentsManager(
305 profile_,
306 base::Bind(&DriveFirstRunController::OnOptInDone,
307 base::Unretained(this))));
308 web_contents_manager_->StartLoad();
309 web_contents_timer_.Start(
310 FROM_HERE,
311 base::TimeDelta::FromSeconds(kWebContentsTimeoutSeconds),
312 this,
313 &DriveFirstRunController::OnWebContentsTimedOut);
314 }
315
316 void DriveFirstRunController::OnWebContentsTimedOut() {
317 LOG(WARNING) << "Timed out waiting for web contents to opt-in";
318 OnOptInDone(false);
319 }
320
321 void DriveFirstRunController::CleanUp() {
322 if (web_contents_manager_)
323 web_contents_manager_->StopLoad();
324 web_contents_timer_.Stop();
325 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
326 }
327
328 void DriveFirstRunController::OnOptInDone(bool success) {
329 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
330 // TODO(tengs): Notify ash system tray to display notice that Drive
331 // offline opt-in has occurred. See crbug.com/311452.
332 CleanUp();
333 }
334
335 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698