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

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

Powered by Google App Engine
This is Rietveld 408576698