| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/background/background_contents_service.h" | 5 #include "chrome/browser/background/background_contents_service.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 // uninstalls the extension. | 209 // uninstalls the extension. |
| 210 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, | 210 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, |
| 211 content::Source<Profile>(profile)); | 211 content::Source<Profile>(profile)); |
| 212 } | 212 } |
| 213 | 213 |
| 214 void BackgroundContentsService::Observe( | 214 void BackgroundContentsService::Observe( |
| 215 int type, | 215 int type, |
| 216 const content::NotificationSource& source, | 216 const content::NotificationSource& source, |
| 217 const content::NotificationDetails& details) { | 217 const content::NotificationDetails& details) { |
| 218 switch (type) { | 218 switch (type) { |
| 219 case chrome::NOTIFICATION_EXTENSIONS_READY: | 219 case chrome::NOTIFICATION_EXTENSIONS_READY: { |
| 220 LoadBackgroundContentsFromManifests( | 220 Profile* profile = content::Source<Profile>(source).ptr(); |
| 221 content::Source<Profile>(source).ptr()); | 221 LoadBackgroundContentsFromManifests(profile); |
| 222 LoadBackgroundContentsFromPrefs(content::Source<Profile>(source).ptr()); | 222 LoadBackgroundContentsFromPrefs(profile); |
| 223 SendChangeNotification(profile); |
| 223 break; | 224 break; |
| 225 } |
| 224 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: | 226 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: |
| 225 BackgroundContentsShutdown( | 227 BackgroundContentsShutdown( |
| 226 content::Details<BackgroundContents>(details).ptr()); | 228 content::Details<BackgroundContents>(details).ptr()); |
| 229 SendChangeNotification(content::Source<Profile>(source).ptr()); |
| 227 break; | 230 break; |
| 228 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_CLOSED: | 231 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_CLOSED: |
| 229 DCHECK(IsTracked(content::Details<BackgroundContents>(details).ptr())); | 232 DCHECK(IsTracked(content::Details<BackgroundContents>(details).ptr())); |
| 230 UnregisterBackgroundContents( | 233 UnregisterBackgroundContents( |
| 231 content::Details<BackgroundContents>(details).ptr()); | 234 content::Details<BackgroundContents>(details).ptr()); |
| 235 // CLOSED is always followed by a DELETED notification so we'll send our |
| 236 // change notification there. |
| 232 break; | 237 break; |
| 233 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: { | 238 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: { |
| 234 DCHECK(IsTracked(content::Details<BackgroundContents>(details).ptr())); | 239 DCHECK(IsTracked(content::Details<BackgroundContents>(details).ptr())); |
| 235 | 240 |
| 236 // Do not register in the pref if the extension has a manifest-specified | 241 // Do not register in the pref if the extension has a manifest-specified |
| 237 // background page. | 242 // background page. |
| 238 BackgroundContents* bgcontents = | 243 BackgroundContents* bgcontents = |
| 239 content::Details<BackgroundContents>(details).ptr(); | 244 content::Details<BackgroundContents>(details).ptr(); |
| 240 Profile* profile = content::Source<Profile>(source).ptr(); | 245 Profile* profile = content::Source<Profile>(source).ptr(); |
| 241 const string16& appid = GetParentApplicationId(bgcontents); | 246 const string16& appid = GetParentApplicationId(bgcontents); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 265 // Now load the manifest-specified background page. If service isn't | 270 // Now load the manifest-specified background page. If service isn't |
| 266 // ready, then the background page will be loaded from the | 271 // ready, then the background page will be loaded from the |
| 267 // EXTENSIONS_READY callback. | 272 // EXTENSIONS_READY callback. |
| 268 LoadBackgroundContents(profile, extension->GetBackgroundURL(), | 273 LoadBackgroundContents(profile, extension->GetBackgroundURL(), |
| 269 ASCIIToUTF16("background"), UTF8ToUTF16(extension->id())); | 274 ASCIIToUTF16("background"), UTF8ToUTF16(extension->id())); |
| 270 } | 275 } |
| 271 } | 276 } |
| 272 | 277 |
| 273 // Remove any "This extension has crashed" balloons. | 278 // Remove any "This extension has crashed" balloons. |
| 274 ScheduleCloseBalloon(extension->id()); | 279 ScheduleCloseBalloon(extension->id()); |
| 280 SendChangeNotification(profile); |
| 275 break; | 281 break; |
| 276 } | 282 } |
| 277 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: | 283 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: |
| 278 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED: { | 284 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED: { |
| 279 Profile* profile = content::Source<Profile>(source).ptr(); | 285 Profile* profile = content::Source<Profile>(source).ptr(); |
| 280 const Extension* extension = NULL; | 286 const Extension* extension = NULL; |
| 281 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED) { | 287 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED) { |
| 282 BackgroundContents* bg = | 288 BackgroundContents* bg = |
| 283 content::Details<BackgroundContents>(details).ptr(); | 289 content::Details<BackgroundContents>(details).ptr(); |
| 284 std::string extension_id = UTF16ToASCII( | 290 std::string extension_id = UTF16ToASCII( |
| (...skipping 19 matching lines...) Expand all Loading... |
| 304 break; | 310 break; |
| 305 } | 311 } |
| 306 case chrome::NOTIFICATION_EXTENSION_UNLOADED: | 312 case chrome::NOTIFICATION_EXTENSION_UNLOADED: |
| 307 switch (content::Details<UnloadedExtensionInfo>(details)->reason) { | 313 switch (content::Details<UnloadedExtensionInfo>(details)->reason) { |
| 308 case extension_misc::UNLOAD_REASON_DISABLE: // Fall through. | 314 case extension_misc::UNLOAD_REASON_DISABLE: // Fall through. |
| 309 case extension_misc::UNLOAD_REASON_TERMINATE: // Fall through. | 315 case extension_misc::UNLOAD_REASON_TERMINATE: // Fall through. |
| 310 case extension_misc::UNLOAD_REASON_UNINSTALL: | 316 case extension_misc::UNLOAD_REASON_UNINSTALL: |
| 311 ShutdownAssociatedBackgroundContents( | 317 ShutdownAssociatedBackgroundContents( |
| 312 ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)-> | 318 ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)-> |
| 313 extension->id())); | 319 extension->id())); |
| 320 SendChangeNotification(content::Source<Profile>(source).ptr()); |
| 314 break; | 321 break; |
| 315 case extension_misc::UNLOAD_REASON_UPDATE: { | 322 case extension_misc::UNLOAD_REASON_UPDATE: { |
| 316 // If there is a manifest specified background page, then shut it down | 323 // If there is a manifest specified background page, then shut it down |
| 317 // here, since if the updated extension still has the background page, | 324 // here, since if the updated extension still has the background page, |
| 318 // then it will be loaded from LOADED callback. Otherwise, leave | 325 // then it will be loaded from LOADED callback. Otherwise, leave |
| 319 // BackgroundContents in place. | 326 // BackgroundContents in place. |
| 327 // We don't call SendChangeNotification here - it will be generated |
| 328 // from the LOADED callback. |
| 320 const Extension* extension = | 329 const Extension* extension = |
| 321 content::Details<UnloadedExtensionInfo>(details)->extension; | 330 content::Details<UnloadedExtensionInfo>(details)->extension; |
| 322 if (extension->has_background_page()) | 331 if (extension->has_background_page()) |
| 323 ShutdownAssociatedBackgroundContents(ASCIIToUTF16(extension->id())); | 332 ShutdownAssociatedBackgroundContents(ASCIIToUTF16(extension->id())); |
| 324 break; | 333 break; |
| 325 } | 334 } |
| 326 default: | 335 default: |
| 327 NOTREACHED(); | 336 NOTREACHED(); |
| 328 ShutdownAssociatedBackgroundContents( | 337 ShutdownAssociatedBackgroundContents( |
| 329 ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)-> | 338 ASCIIToUTF16(content::Details<UnloadedExtensionInfo>(details)-> |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 NOTREACHED() << "No extension found for BackgroundContents - id = " | 378 NOTREACHED() << "No extension found for BackgroundContents - id = " |
| 370 << *it; | 379 << *it; |
| 371 // Don't cancel out of our loop, just ignore this BackgroundContents and | 380 // Don't cancel out of our loop, just ignore this BackgroundContents and |
| 372 // load the next one. | 381 // load the next one. |
| 373 continue; | 382 continue; |
| 374 } | 383 } |
| 375 LoadBackgroundContentsFromDictionary(profile, *it, contents); | 384 LoadBackgroundContentsFromDictionary(profile, *it, contents); |
| 376 } | 385 } |
| 377 } | 386 } |
| 378 | 387 |
| 388 void BackgroundContentsService::SendChangeNotification(Profile* profile) { |
| 389 content::NotificationService::current()->Notify( |
| 390 chrome::NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED, |
| 391 content::Source<Profile>(profile), |
| 392 content::Details<BackgroundContentsService>(this)); |
| 393 } |
| 394 |
| 379 void BackgroundContentsService::LoadBackgroundContentsForExtension( | 395 void BackgroundContentsService::LoadBackgroundContentsForExtension( |
| 380 Profile* profile, | 396 Profile* profile, |
| 381 const std::string& extension_id) { | 397 const std::string& extension_id) { |
| 382 // First look if the manifest specifies a background page. | 398 // First look if the manifest specifies a background page. |
| 383 const Extension* extension = | 399 const Extension* extension = |
| 384 profile->GetExtensionService()->GetExtensionById(extension_id, false); | 400 profile->GetExtensionService()->GetExtensionById(extension_id, false); |
| 385 DCHECK(!extension || extension->is_hosted_app()); | 401 DCHECK(!extension || extension->is_hosted_app()); |
| 386 if (extension && extension->has_background_page()) { | 402 if (extension && extension->has_background_page()) { |
| 387 LoadBackgroundContents(profile, | 403 LoadBackgroundContents(profile, |
| 388 extension->GetBackgroundURL(), | 404 extension->GetBackgroundURL(), |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 // Register the BackgroundContents internally, then send out a notification | 492 // Register the BackgroundContents internally, then send out a notification |
| 477 // to external listeners. | 493 // to external listeners. |
| 478 BackgroundContentsOpenedDetails details = {contents, | 494 BackgroundContentsOpenedDetails details = {contents, |
| 479 frame_name, | 495 frame_name, |
| 480 application_id}; | 496 application_id}; |
| 481 BackgroundContentsOpened(&details); | 497 BackgroundContentsOpened(&details); |
| 482 content::NotificationService::current()->Notify( | 498 content::NotificationService::current()->Notify( |
| 483 chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, | 499 chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, |
| 484 content::Source<Profile>(profile), | 500 content::Source<Profile>(profile), |
| 485 content::Details<BackgroundContentsOpenedDetails>(&details)); | 501 content::Details<BackgroundContentsOpenedDetails>(&details)); |
| 502 |
| 503 // A new background contents has been created - notify our listeners. |
| 504 SendChangeNotification(profile); |
| 486 return contents; | 505 return contents; |
| 487 } | 506 } |
| 488 | 507 |
| 489 void BackgroundContentsService::RegisterBackgroundContents( | 508 void BackgroundContentsService::RegisterBackgroundContents( |
| 490 BackgroundContents* background_contents) { | 509 BackgroundContents* background_contents) { |
| 491 DCHECK(IsTracked(background_contents)); | 510 DCHECK(IsTracked(background_contents)); |
| 492 if (!prefs_) | 511 if (!prefs_) |
| 493 return; | 512 return; |
| 494 | 513 |
| 495 // We store the first URL we receive for a given application. If there's | 514 // We store the first URL we receive for a given application. If there's |
| 496 // already an entry for this application, no need to do anything. | 515 // already an entry for this application, no need to do anything. |
| 497 // TODO(atwilson): Verify that this is the desired behavior based on developer | 516 // TODO(atwilson): Verify that this is the desired behavior based on developer |
| 498 // feedback (http://crbug.com/47118). | 517 // feedback (http://crbug.com/47118). |
| 499 DictionaryPrefUpdate update(prefs_, prefs::kRegisteredBackgroundContents); | 518 DictionaryPrefUpdate update(prefs_, prefs::kRegisteredBackgroundContents); |
| 500 DictionaryValue* pref = update.Get(); | 519 DictionaryValue* pref = update.Get(); |
| 501 const string16& appid = GetParentApplicationId(background_contents); | 520 const string16& appid = GetParentApplicationId(background_contents); |
| 502 DictionaryValue* current; | 521 DictionaryValue* current; |
| 503 if (pref->GetDictionaryWithoutPathExpansion(UTF16ToUTF8(appid), ¤t)) | 522 if (pref->GetDictionaryWithoutPathExpansion(UTF16ToUTF8(appid), ¤t)) |
| 504 return; | 523 return; |
| 505 | 524 |
| 506 // No entry for this application yet, so add one. | 525 // No entry for this application yet, so add one. |
| 507 DictionaryValue* dict = new DictionaryValue(); | 526 DictionaryValue* dict = new DictionaryValue(); |
| 508 dict->SetString(kUrlKey, background_contents->GetURL().spec()); | 527 dict->SetString(kUrlKey, background_contents->GetURL().spec()); |
| 509 dict->SetString(kFrameNameKey, contents_map_[appid].frame_name); | 528 dict->SetString(kFrameNameKey, contents_map_[appid].frame_name); |
| 510 pref->SetWithoutPathExpansion(UTF16ToUTF8(appid), dict); | 529 pref->SetWithoutPathExpansion(UTF16ToUTF8(appid), dict); |
| 511 } | 530 } |
| 512 | 531 |
| 532 bool BackgroundContentsService::HasRegisteredBackgroundContents( |
| 533 const string16& app_id) { |
| 534 if (!prefs_) |
| 535 return false; |
| 536 std::string app = UTF16ToUTF8(app_id); |
| 537 const DictionaryValue* contents = |
| 538 prefs_->GetDictionary(prefs::kRegisteredBackgroundContents); |
| 539 return contents->HasKey(app); |
| 540 } |
| 541 |
| 513 void BackgroundContentsService::UnregisterBackgroundContents( | 542 void BackgroundContentsService::UnregisterBackgroundContents( |
| 514 BackgroundContents* background_contents) { | 543 BackgroundContents* background_contents) { |
| 515 if (!prefs_) | 544 if (!prefs_) |
| 516 return; | 545 return; |
| 517 DCHECK(IsTracked(background_contents)); | 546 DCHECK(IsTracked(background_contents)); |
| 518 const string16 appid = GetParentApplicationId(background_contents); | 547 const string16 appid = GetParentApplicationId(background_contents); |
| 519 DictionaryPrefUpdate update(prefs_, prefs::kRegisteredBackgroundContents); | 548 DictionaryPrefUpdate update(prefs_, prefs::kRegisteredBackgroundContents); |
| 520 update.Get()->RemoveWithoutPathExpansion(UTF16ToUTF8(appid), NULL); | 549 update.Get()->RemoveWithoutPathExpansion(UTF16ToUTF8(appid), NULL); |
| 521 } | 550 } |
| 522 | 551 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 WebContents* new_contents, | 605 WebContents* new_contents, |
| 577 WindowOpenDisposition disposition, | 606 WindowOpenDisposition disposition, |
| 578 const gfx::Rect& initial_pos, | 607 const gfx::Rect& initial_pos, |
| 579 bool user_gesture) { | 608 bool user_gesture) { |
| 580 Browser* browser = BrowserList::GetLastActiveWithProfile( | 609 Browser* browser = BrowserList::GetLastActiveWithProfile( |
| 581 Profile::FromBrowserContext(new_contents->GetBrowserContext())); | 610 Profile::FromBrowserContext(new_contents->GetBrowserContext())); |
| 582 if (!browser) | 611 if (!browser) |
| 583 return; | 612 return; |
| 584 browser->AddWebContents(new_contents, disposition, initial_pos, user_gesture); | 613 browser->AddWebContents(new_contents, disposition, initial_pos, user_gesture); |
| 585 } | 614 } |
| OLD | NEW |