OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h" | 5 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
8 #include "ash/system/tray/system_tray_notifier.h" | 8 #include "ash/system/tray/system_tray_notifier.h" |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/memory/weak_ptr.h" | 10 #include "base/memory/weak_ptr.h" |
11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
13 #include "chrome/browser/background/background_contents_service.h" | 13 #include "chrome/browser/background/background_contents_service.h" |
14 #include "chrome/browser/background/background_contents_service_factory.h" | 14 #include "chrome/browser/background/background_contents_service_factory.h" |
15 #include "chrome/browser/chrome_notification_types.h" | 15 #include "chrome/browser/chrome_notification_types.h" |
16 #include "chrome/browser/chromeos/login/user_manager.h" | 16 #include "chrome/browser/chromeos/login/user_manager.h" |
17 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
18 #include "chrome/browser/extensions/extension_system.h" | 18 #include "chrome/browser/extensions/extension_system.h" |
| 19 #include "chrome/browser/extensions/extension_web_contents_observer.h" |
19 #include "chrome/browser/profiles/profile_manager.h" | 20 #include "chrome/browser/profiles/profile_manager.h" |
20 #include "chrome/browser/tab_contents/background_contents.h" | 21 #include "chrome/browser/tab_contents/background_contents.h" |
21 #include "chrome/common/extensions/extension.h" | 22 #include "chrome/common/extensions/extension.h" |
22 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
23 #include "content/public/browser/navigation_controller.h" | 24 #include "content/public/browser/navigation_controller.h" |
24 #include "content/public/browser/notification_details.h" | 25 #include "content/public/browser/notification_details.h" |
25 #include "content/public/browser/notification_observer.h" | 26 #include "content/public/browser/notification_observer.h" |
26 #include "content/public/browser/notification_registrar.h" | 27 #include "content/public/browser/notification_registrar.h" |
27 #include "content/public/browser/notification_source.h" | 28 #include "content/public/browser/notification_source.h" |
28 #include "content/public/browser/notification_types.h" | 29 #include "content/public/browser/notification_types.h" |
29 #include "content/public/browser/site_instance.h" | 30 #include "content/public/browser/site_instance.h" |
30 #include "content/public/browser/web_contents.h" | 31 #include "content/public/browser/web_contents.h" |
31 #include "content/public/browser/web_contents_observer.h" | 32 #include "content/public/browser/web_contents_observer.h" |
32 #include "url/gurl.h" | 33 #include "url/gurl.h" |
33 | 34 |
34 namespace chromeos { | 35 namespace chromeos { |
35 | 36 |
36 namespace { | 37 namespace { |
37 | 38 |
38 // The initial time to wait in seconds before starting the opt-in. | 39 // The initial time to wait in seconds before starting the opt-in. |
39 const int kInitialDelaySeconds = 180; | 40 int kInitialDelaySeconds = 180; |
40 | 41 |
41 // Time to wait for Drive app background page to come up before giving up. | 42 // Time to wait for Drive app background page to come up before giving up. |
42 const int kWebContentsTimeoutSeconds = 15; | 43 int kWebContentsTimeoutSeconds = 15; |
43 | 44 |
44 // Google Drive offline opt-in endpoint. | 45 // Google Drive offline opt-in endpoint. |
45 const char kDriveOfflineEndpointUrl[] = "https://drive.google.com/#offline"; | 46 const char kDriveOfflineEndpointUrl[] = "https://drive.google.com/#offline"; |
46 | 47 |
47 // Google Drive app id. | 48 // Google Drive app id. |
48 const char kDriveHostedAppId[] = "apdfllckaahabafndbhieahigkjlhalf"; | 49 const char kDriveHostedAppId[] = "apdfllckaahabafndbhieahigkjlhalf"; |
49 | 50 |
50 } // namespace | 51 } // namespace |
51 | 52 |
52 //////////////////////////////////////////////////////////////////////////////// | 53 //////////////////////////////////////////////////////////////////////////////// |
53 // DriveWebContentsManager | 54 // DriveWebContentsManager |
54 | 55 |
55 // Manages web contents that does Google Drive offline opt-in. We create | 56 // Manages web contents that does Google Drive offline opt-in. We create |
56 // a background WebContents that loads a Drive endpoint to initialize offline | 57 // a background WebContents that loads a Drive endpoint to initialize offline |
57 // mode. If successful, a background page will be opened to sync the user's | 58 // mode. If successful, a background page will be opened to sync the user's |
58 // files for offline use. | 59 // files for offline use. |
59 class DriveWebContentsManager : public content::WebContentsObserver, | 60 class DriveWebContentsManager : public content::WebContentsObserver, |
60 public content::WebContentsDelegate, | 61 public content::WebContentsDelegate, |
61 public content::NotificationObserver { | 62 public content::NotificationObserver { |
62 public: | 63 public: |
63 typedef base::Callback<void(bool)> CompletionCallback; | 64 typedef base::Callback<void(bool)> CompletionCallback; |
64 | 65 |
65 DriveWebContentsManager(Profile* profile, | 66 DriveWebContentsManager(Profile* profile, |
| 67 const std::string& app_id, |
| 68 const std::string& endpoint_url, |
66 const CompletionCallback& completion_callback); | 69 const CompletionCallback& completion_callback); |
67 virtual ~DriveWebContentsManager(); | 70 virtual ~DriveWebContentsManager(); |
68 | 71 |
69 // Start loading the WebContents for the endpoint in the context of the Drive | 72 // Start loading the WebContents for the endpoint in the context of the Drive |
70 // hosted app that will initialize offline mode and open a background page. | 73 // hosted app that will initialize offline mode and open a background page. |
71 void StartLoad(); | 74 void StartLoad(); |
72 | 75 |
73 // Stop loading the endpoint. The |completion_callback| will not be called. | 76 // Stop loading the endpoint. The |completion_callback| will not be called. |
74 void StopLoad(); | 77 void StopLoad(); |
75 | 78 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 const GURL& target_url, | 110 const GURL& target_url, |
108 const std::string& partition_id, | 111 const std::string& partition_id, |
109 content::SessionStorageNamespace* session_storage_namespace) OVERRIDE; | 112 content::SessionStorageNamespace* session_storage_namespace) OVERRIDE; |
110 | 113 |
111 // content::NotificationObserver overrides: | 114 // content::NotificationObserver overrides: |
112 virtual void Observe(int type, | 115 virtual void Observe(int type, |
113 const content::NotificationSource& source, | 116 const content::NotificationSource& source, |
114 const content::NotificationDetails& details) OVERRIDE; | 117 const content::NotificationDetails& details) OVERRIDE; |
115 | 118 |
116 Profile* profile_; | 119 Profile* profile_; |
| 120 const std::string app_id_; |
| 121 const std::string endpoint_url_; |
117 scoped_ptr<content::WebContents> web_contents_; | 122 scoped_ptr<content::WebContents> web_contents_; |
118 content::NotificationRegistrar registrar_; | 123 content::NotificationRegistrar registrar_; |
119 bool started_; | 124 bool started_; |
120 CompletionCallback completion_callback_; | 125 CompletionCallback completion_callback_; |
121 base::WeakPtrFactory<DriveWebContentsManager> weak_ptr_factory_; | 126 base::WeakPtrFactory<DriveWebContentsManager> weak_ptr_factory_; |
122 | 127 |
123 DISALLOW_COPY_AND_ASSIGN(DriveWebContentsManager); | 128 DISALLOW_COPY_AND_ASSIGN(DriveWebContentsManager); |
124 }; | 129 }; |
125 | 130 |
126 DriveWebContentsManager::DriveWebContentsManager( | 131 DriveWebContentsManager::DriveWebContentsManager( |
127 Profile* profile, | 132 Profile* profile, |
| 133 const std::string& app_id, |
| 134 const std::string& endpoint_url, |
128 const CompletionCallback& completion_callback) | 135 const CompletionCallback& completion_callback) |
129 : profile_(profile), | 136 : profile_(profile), |
| 137 app_id_(app_id), |
| 138 endpoint_url_(endpoint_url), |
130 started_(false), | 139 started_(false), |
131 completion_callback_(completion_callback), | 140 completion_callback_(completion_callback), |
132 weak_ptr_factory_(this) { | 141 weak_ptr_factory_(this) { |
133 DCHECK(!completion_callback_.is_null()); | 142 DCHECK(!completion_callback_.is_null()); |
134 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, | 143 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, |
135 content::Source<Profile>(profile_)); | 144 content::Source<Profile>(profile_)); |
136 } | 145 } |
137 | 146 |
138 DriveWebContentsManager::~DriveWebContentsManager() { | 147 DriveWebContentsManager::~DriveWebContentsManager() { |
139 } | 148 } |
140 | 149 |
141 void DriveWebContentsManager::StartLoad() { | 150 void DriveWebContentsManager::StartLoad() { |
142 started_ = true; | 151 started_ = true; |
143 const GURL url(kDriveOfflineEndpointUrl); | 152 const GURL url(endpoint_url_); |
144 content::WebContents::CreateParams create_params( | 153 content::WebContents::CreateParams create_params( |
145 profile_, content::SiteInstance::CreateForURL(profile_, url)); | 154 profile_, content::SiteInstance::CreateForURL(profile_, url)); |
146 | 155 |
147 web_contents_.reset(content::WebContents::Create(create_params)); | 156 web_contents_.reset(content::WebContents::Create(create_params)); |
148 web_contents_->SetDelegate(this); | 157 web_contents_->SetDelegate(this); |
| 158 extensions::ExtensionWebContentsObserver::CreateForWebContents( |
| 159 web_contents_.get()); |
149 | 160 |
150 content::NavigationController::LoadURLParams load_params(url); | 161 content::NavigationController::LoadURLParams load_params(url); |
151 load_params.transition_type = content::PAGE_TRANSITION_GENERATED; | 162 load_params.transition_type = content::PAGE_TRANSITION_GENERATED; |
152 web_contents_->GetController().LoadURLWithParams(load_params); | 163 web_contents_->GetController().LoadURLWithParams(load_params); |
153 | 164 |
154 content::WebContentsObserver::Observe(web_contents_.get()); | 165 content::WebContentsObserver::Observe(web_contents_.get()); |
155 } | 166 } |
156 | 167 |
157 void DriveWebContentsManager::StopLoad() { | 168 void DriveWebContentsManager::StopLoad() { |
158 started_ = false; | 169 started_ = false; |
(...skipping 17 matching lines...) Expand all Loading... |
176 } | 187 } |
177 | 188 |
178 void DriveWebContentsManager::DidFailProvisionalLoad( | 189 void DriveWebContentsManager::DidFailProvisionalLoad( |
179 int64 frame_id, | 190 int64 frame_id, |
180 const string16& frame_unique_name, | 191 const string16& frame_unique_name, |
181 bool is_main_frame, | 192 bool is_main_frame, |
182 const GURL& validated_url, | 193 const GURL& validated_url, |
183 int error_code, | 194 int error_code, |
184 const string16& error_description, | 195 const string16& error_description, |
185 content::RenderViewHost* render_view_host) { | 196 content::RenderViewHost* render_view_host) { |
186 OnOfflineInit(false); | 197 if (is_main_frame) { |
| 198 LOG(WARNING) << "Failed to load WebContents to enable offline mode."; |
| 199 OnOfflineInit(false); |
| 200 } |
187 } | 201 } |
188 | 202 |
189 void DriveWebContentsManager::DidFailLoad( | 203 void DriveWebContentsManager::DidFailLoad( |
190 int64 frame_id, | 204 int64 frame_id, |
191 const GURL& validated_url, | 205 const GURL& validated_url, |
192 bool is_main_frame, | 206 bool is_main_frame, |
193 int error_code, | 207 int error_code, |
194 const string16& error_description, | 208 const string16& error_description, |
195 content::RenderViewHost* render_view_host) { | 209 content::RenderViewHost* render_view_host) { |
196 OnOfflineInit(false); | 210 if (is_main_frame) { |
| 211 LOG(WARNING) << "Failed to load WebContents to enable offline mode."; |
| 212 OnOfflineInit(false); |
| 213 } |
197 } | 214 } |
198 | 215 |
199 bool DriveWebContentsManager::ShouldCreateWebContents( | 216 bool DriveWebContentsManager::ShouldCreateWebContents( |
200 content::WebContents* web_contents, | 217 content::WebContents* web_contents, |
201 int route_id, | 218 int route_id, |
202 WindowContainerType window_container_type, | 219 WindowContainerType window_container_type, |
203 const string16& frame_name, | 220 const string16& frame_name, |
204 const GURL& target_url, | 221 const GURL& target_url, |
205 const std::string& partition_id, | 222 const std::string& partition_id, |
206 content::SessionStorageNamespace* session_storage_namespace) { | 223 content::SessionStorageNamespace* session_storage_namespace) { |
207 | 224 |
208 if (window_container_type == WINDOW_CONTAINER_TYPE_NORMAL) | 225 if (window_container_type == WINDOW_CONTAINER_TYPE_NORMAL) |
209 return true; | 226 return true; |
210 | 227 |
211 // Check that the target URL is for the Drive app. | 228 // Check that the target URL is for the Drive app. |
212 ExtensionService* service = | 229 ExtensionService* service = |
213 extensions::ExtensionSystem::Get(profile_)->extension_service(); | 230 extensions::ExtensionSystem::Get(profile_)->extension_service(); |
214 const extensions::Extension *extension = | 231 const extensions::Extension *extension = |
215 service->GetInstalledApp(target_url); | 232 service->GetInstalledApp(target_url); |
216 if (!extension || extension->id() != kDriveHostedAppId) | 233 if (!extension || extension->id() != app_id_) |
217 return true; | 234 return true; |
218 | 235 |
219 // The background contents creation is normally done in Browser, but | 236 // The background contents creation is normally done in Browser, but |
220 // because we're using a detached WebContents, we need to do it ourselves. | 237 // because we're using a detached WebContents, we need to do it ourselves. |
221 BackgroundContentsService* background_contents_service = | 238 BackgroundContentsService* background_contents_service = |
222 BackgroundContentsServiceFactory::GetForProfile(profile_); | 239 BackgroundContentsServiceFactory::GetForProfile(profile_); |
223 | 240 |
224 // Prevent redirection if background contents already exists. | 241 // Prevent redirection if background contents already exists. |
225 if (background_contents_service->GetAppBackgroundContents( | 242 if (background_contents_service->GetAppBackgroundContents( |
226 UTF8ToUTF16(kDriveHostedAppId))) { | 243 UTF8ToUTF16(app_id_))) { |
227 return false; | 244 return false; |
228 } | 245 } |
229 BackgroundContents* contents = background_contents_service | 246 BackgroundContents* contents = background_contents_service |
230 ->CreateBackgroundContents(content::SiteInstance::Create(profile_), | 247 ->CreateBackgroundContents(content::SiteInstance::Create(profile_), |
231 route_id, | 248 route_id, |
232 profile_, | 249 profile_, |
233 frame_name, | 250 frame_name, |
234 ASCIIToUTF16(kDriveHostedAppId), | 251 ASCIIToUTF16(app_id_), |
235 partition_id, | 252 partition_id, |
236 session_storage_namespace); | 253 session_storage_namespace); |
237 | 254 |
238 contents->web_contents()->GetController().LoadURL( | 255 contents->web_contents()->GetController().LoadURL( |
239 target_url, | 256 target_url, |
240 content::Referrer(), | 257 content::Referrer(), |
241 content::PAGE_TRANSITION_LINK, | 258 content::PAGE_TRANSITION_LINK, |
242 std::string()); | 259 std::string()); |
243 | 260 |
244 // Return false as we already created the WebContents here. | 261 // Return false as we already created the WebContents here. |
245 return false; | 262 return false; |
246 } | 263 } |
247 | 264 |
248 void DriveWebContentsManager::Observe( | 265 void DriveWebContentsManager::Observe( |
249 int type, | 266 int type, |
250 const content::NotificationSource& source, | 267 const content::NotificationSource& source, |
251 const content::NotificationDetails& details) { | 268 const content::NotificationDetails& details) { |
252 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED) { | 269 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED) { |
253 const std::string app_id = UTF16ToUTF8( | 270 const std::string app_id = UTF16ToUTF8( |
254 content::Details<BackgroundContentsOpenedDetails>(details) | 271 content::Details<BackgroundContentsOpenedDetails>(details) |
255 ->application_id); | 272 ->application_id); |
256 if (app_id == kDriveHostedAppId) | 273 if (app_id == app_id_) |
257 OnOfflineInit(true); | 274 OnOfflineInit(true); |
258 } | 275 } |
259 } | 276 } |
260 | 277 |
261 //////////////////////////////////////////////////////////////////////////////// | 278 //////////////////////////////////////////////////////////////////////////////// |
262 // DriveFirstRunController | 279 // DriveFirstRunController |
263 | 280 |
264 DriveFirstRunController::DriveFirstRunController() | 281 DriveFirstRunController::DriveFirstRunController() |
265 : profile_(ProfileManager::GetDefaultProfile()), | 282 : profile_(ProfileManager::GetDefaultProfile()), |
266 started_(false) { | 283 started_(false), |
| 284 initial_delay_secs_(kInitialDelaySeconds), |
| 285 web_contents_timeout_secs_(kWebContentsTimeoutSeconds), |
| 286 drive_offline_endpoint_url_(kDriveOfflineEndpointUrl), |
| 287 drive_hosted_app_id_(kDriveHostedAppId) { |
267 } | 288 } |
268 | 289 |
269 DriveFirstRunController::~DriveFirstRunController() { | 290 DriveFirstRunController::~DriveFirstRunController() { |
270 } | 291 } |
271 | 292 |
272 void DriveFirstRunController::EnableOfflineMode() { | 293 void DriveFirstRunController::EnableOfflineMode() { |
273 if (!started_) { | 294 if (!started_) { |
274 started_ = true; | 295 started_ = true; |
275 initial_delay_timer_.Start( | 296 initial_delay_timer_.Start( |
276 FROM_HERE, | 297 FROM_HERE, |
277 base::TimeDelta::FromSeconds(kInitialDelaySeconds), | 298 base::TimeDelta::FromSeconds(initial_delay_secs_), |
278 this, | 299 this, |
279 &DriveFirstRunController::EnableOfflineMode); | 300 &DriveFirstRunController::EnableOfflineMode); |
280 return; | 301 return; |
281 } | 302 } |
282 | 303 |
283 if (!UserManager::Get()->IsLoggedInAsRegularUser()) { | 304 if (!UserManager::Get()->IsLoggedInAsRegularUser()) { |
284 LOG(ERROR) << "Attempting to enable offline access " | 305 LOG(ERROR) << "Attempting to enable offline access " |
285 "but not logged in a regular user."; | 306 "but not logged in a regular user."; |
286 OnOfflineInit(false); | 307 OnOfflineInit(false); |
287 return; | 308 return; |
288 } | 309 } |
289 | 310 |
290 ExtensionService* extension_service = | 311 ExtensionService* extension_service = |
291 extensions::ExtensionSystem::Get(profile_)->extension_service(); | 312 extensions::ExtensionSystem::Get(profile_)->extension_service(); |
292 if (!extension_service->GetExtensionById(kDriveHostedAppId, false)) { | 313 if (!extension_service->GetExtensionById(drive_hosted_app_id_, false)) { |
293 LOG(WARNING) << "Drive app is not installed."; | 314 LOG(WARNING) << "Drive app is not installed."; |
294 OnOfflineInit(false); | 315 OnOfflineInit(false); |
295 return; | 316 return; |
296 } | 317 } |
297 | 318 |
298 BackgroundContentsService* background_contents_service = | 319 BackgroundContentsService* background_contents_service = |
299 BackgroundContentsServiceFactory::GetForProfile(profile_); | 320 BackgroundContentsServiceFactory::GetForProfile(profile_); |
300 if (background_contents_service->GetAppBackgroundContents( | 321 if (background_contents_service->GetAppBackgroundContents( |
301 UTF8ToUTF16(kDriveHostedAppId))) { | 322 UTF8ToUTF16(drive_hosted_app_id_))) { |
302 LOG(WARNING) << "Background page for Drive app already exists"; | 323 LOG(WARNING) << "Background page for Drive app already exists"; |
303 OnOfflineInit(false); | 324 OnOfflineInit(false); |
304 return; | 325 return; |
305 } | 326 } |
306 | 327 |
307 web_contents_manager_.reset(new DriveWebContentsManager( | 328 web_contents_manager_.reset(new DriveWebContentsManager( |
308 profile_, | 329 profile_, |
| 330 drive_hosted_app_id_, |
| 331 drive_offline_endpoint_url_, |
309 base::Bind(&DriveFirstRunController::OnOfflineInit, | 332 base::Bind(&DriveFirstRunController::OnOfflineInit, |
310 base::Unretained(this)))); | 333 base::Unretained(this)))); |
311 web_contents_manager_->StartLoad(); | 334 web_contents_manager_->StartLoad(); |
312 web_contents_timer_.Start( | 335 web_contents_timer_.Start( |
313 FROM_HERE, | 336 FROM_HERE, |
314 base::TimeDelta::FromSeconds(kWebContentsTimeoutSeconds), | 337 base::TimeDelta::FromSeconds(web_contents_timeout_secs_), |
315 this, | 338 this, |
316 &DriveFirstRunController::OnWebContentsTimedOut); | 339 &DriveFirstRunController::OnWebContentsTimedOut); |
317 } | 340 } |
318 | 341 |
| 342 void DriveFirstRunController::AddObserver(Observer* observer) { |
| 343 observer_list_.AddObserver(observer); |
| 344 } |
| 345 |
| 346 void DriveFirstRunController::RemoveObserver(Observer* observer) { |
| 347 observer_list_.RemoveObserver(observer); |
| 348 } |
| 349 |
| 350 void DriveFirstRunController::SetDelaysForTest(int initial_delay_secs, |
| 351 int timeout_secs) { |
| 352 DCHECK(!started_); |
| 353 initial_delay_secs_ = initial_delay_secs; |
| 354 web_contents_timeout_secs_ = timeout_secs; |
| 355 } |
| 356 |
| 357 void DriveFirstRunController::SetAppInfoForTest( |
| 358 const std::string& app_id, |
| 359 const std::string& endpoint_url) { |
| 360 DCHECK(!started_); |
| 361 drive_hosted_app_id_ = app_id; |
| 362 drive_offline_endpoint_url_ = endpoint_url; |
| 363 } |
| 364 |
319 void DriveFirstRunController::OnWebContentsTimedOut() { | 365 void DriveFirstRunController::OnWebContentsTimedOut() { |
320 LOG(WARNING) << "Timed out waiting for web contents to opt-in"; | 366 LOG(WARNING) << "Timed out waiting for web contents to opt-in"; |
| 367 FOR_EACH_OBSERVER(Observer, observer_list_, OnTimedOut()); |
321 OnOfflineInit(false); | 368 OnOfflineInit(false); |
322 } | 369 } |
323 | 370 |
324 void DriveFirstRunController::CleanUp() { | 371 void DriveFirstRunController::CleanUp() { |
325 if (web_contents_manager_) | 372 if (web_contents_manager_) |
326 web_contents_manager_->StopLoad(); | 373 web_contents_manager_->StopLoad(); |
327 web_contents_timer_.Stop(); | 374 web_contents_timer_.Stop(); |
328 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 375 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
329 } | 376 } |
330 | 377 |
331 void DriveFirstRunController::OnOfflineInit(bool success) { | 378 void DriveFirstRunController::OnOfflineInit(bool success) { |
332 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 379 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
333 ash::Shell::GetInstance()->system_tray_notifier() | 380 if (success) { |
334 ->NotifyDriveOfflineEnabled(); | 381 ash::Shell::GetInstance()->system_tray_notifier() |
| 382 ->NotifyDriveOfflineEnabled(); |
| 383 } |
| 384 FOR_EACH_OBSERVER(Observer, observer_list_, OnCompletion(success)); |
335 CleanUp(); | 385 CleanUp(); |
336 } | 386 } |
337 | 387 |
338 } // namespace chromeos | 388 } // namespace chromeos |
OLD | NEW |