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/extensions/api/tabs/tabs_event_router.h" | 5 #include "chrome/browser/extensions/api/tabs/tabs_event_router.h" |
6 | 6 |
7 #include "base/json/json_writer.h" | 7 #include "base/json/json_writer.h" |
8 #include "base/values.h" | 8 #include "base/values.h" |
9 #include "chrome/browser/chrome_notification_types.h" | 9 #include "chrome/browser/chrome_notification_types.h" |
10 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" | 10 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" |
11 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h" | 11 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h" |
12 #include "chrome/browser/extensions/api/tabs/windows_event_router.h" | 12 #include "chrome/browser/extensions/api/tabs/windows_event_router.h" |
13 #include "chrome/browser/extensions/extension_tab_util.h" | 13 #include "chrome/browser/extensions/extension_tab_util.h" |
14 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
15 #include "chrome/browser/ui/browser.h" | 15 #include "chrome/browser/ui/browser.h" |
16 #include "chrome/browser/ui/browser_iterator.h" | 16 #include "chrome/browser/ui/browser_iterator.h" |
17 #include "chrome/browser/ui/browser_list.h" | 17 #include "chrome/browser/ui/browser_list.h" |
18 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 18 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
19 #include "chrome/browser/ui/tabs/tab_utils.h" | |
19 #include "chrome/common/extensions/extension_constants.h" | 20 #include "chrome/common/extensions/extension_constants.h" |
20 #include "content/public/browser/favicon_status.h" | 21 #include "content/public/browser/favicon_status.h" |
21 #include "content/public/browser/navigation_controller.h" | 22 #include "content/public/browser/navigation_controller.h" |
22 #include "content/public/browser/navigation_entry.h" | 23 #include "content/public/browser/navigation_entry.h" |
23 #include "content/public/browser/notification_service.h" | 24 #include "content/public/browser/notification_service.h" |
24 #include "content/public/browser/notification_types.h" | 25 #include "content/public/browser/notification_types.h" |
25 #include "content/public/browser/web_contents.h" | 26 #include "content/public/browser/web_contents.h" |
26 | 27 |
27 using base::DictionaryValue; | 28 using base::DictionaryValue; |
28 using base::ListValue; | 29 using base::ListValue; |
(...skipping 22 matching lines...) Expand all Loading... | |
51 properties_value); | 52 properties_value); |
52 event_args->Set(1, properties_value); | 53 event_args->Set(1, properties_value); |
53 | 54 |
54 // Overwrite the third arg with our tab value as seen by this extension. | 55 // Overwrite the third arg with our tab value as seen by this extension. |
55 event_args->Set(2, ExtensionTabUtil::CreateTabValue(contents, extension)); | 56 event_args->Set(2, ExtensionTabUtil::CreateTabValue(contents, extension)); |
56 return true; | 57 return true; |
57 } | 58 } |
58 | 59 |
59 } // namespace | 60 } // namespace |
60 | 61 |
61 TabsEventRouter::TabEntry::TabEntry() : complete_waiting_on_load_(false), | 62 TabsEventRouter::TabEntry::TabEntry() |
62 url_() { | 63 : contents_(NULL), |
64 complete_waiting_on_load_(false), | |
65 was_audible_(false), | |
66 was_muted_(false), | |
67 url_() { | |
not at google - send to devlin
2015/03/16 18:11:54
It's not necessary to initialize url()
| |
63 } | 68 } |
64 | 69 |
65 base::DictionaryValue* TabsEventRouter::TabEntry::UpdateLoadState( | 70 TabsEventRouter::TabEntry::TabEntry(content::WebContents* contents) |
66 const WebContents* contents) { | 71 : contents_(contents), |
72 complete_waiting_on_load_(false), | |
73 was_audible_(contents->WasRecentlyAudible()), | |
74 was_muted_(contents->IsAudioMuted()), | |
75 url_() { | |
76 } | |
77 | |
78 DictionaryBuilder* TabsEventRouter::TabEntry::UpdateLoadState() { | |
67 // The tab may go in & out of loading (for instance if iframes navigate). | 79 // The tab may go in & out of loading (for instance if iframes navigate). |
68 // We only want to respond to the first change from loading to !loading after | 80 // We only want to respond to the first change from loading to !loading after |
69 // the NAV_ENTRY_COMMITTED was fired. | 81 // the NAV_ENTRY_COMMITTED was fired. |
70 if (!complete_waiting_on_load_ || contents->IsLoading()) | 82 if (!complete_waiting_on_load_ || contents_->IsLoading()) { |
71 return NULL; | 83 return new DictionaryBuilder(); |
84 } | |
72 | 85 |
73 // Send "complete" state change. | 86 // Send "complete" state change. |
74 complete_waiting_on_load_ = false; | 87 complete_waiting_on_load_ = false; |
75 base::DictionaryValue* changed_properties = new base::DictionaryValue(); | 88 DictionaryBuilder* changed_properties = new DictionaryBuilder(); |
76 changed_properties->SetString(tabs_constants::kStatusKey, | 89 changed_properties->Set(tabs_constants::kStatusKey, |
77 tabs_constants::kStatusValueComplete); | 90 tabs_constants::kStatusValueComplete); |
78 return changed_properties; | 91 return changed_properties; |
not at google - send to devlin
2015/03/16 18:11:55
Builder lets you do:
return DictionaryValue()
| |
79 } | 92 } |
80 | 93 |
81 base::DictionaryValue* TabsEventRouter::TabEntry::DidNavigate( | 94 DictionaryBuilder* TabsEventRouter::TabEntry::DidNavigate() { |
82 const WebContents* contents) { | |
83 // Send "loading" state change. | 95 // Send "loading" state change. |
84 complete_waiting_on_load_ = true; | 96 complete_waiting_on_load_ = true; |
85 base::DictionaryValue* changed_properties = new base::DictionaryValue(); | 97 DictionaryBuilder* changed_properties = new DictionaryBuilder(); |
86 changed_properties->SetString(tabs_constants::kStatusKey, | 98 changed_properties->Set(tabs_constants::kStatusKey, |
87 tabs_constants::kStatusValueLoading); | 99 tabs_constants::kStatusValueLoading); |
88 | 100 |
89 if (contents->GetURL() != url_) { | 101 if (contents_->GetURL() != url_) { |
90 url_ = contents->GetURL(); | 102 url_ = contents_->GetURL(); |
91 changed_properties->SetString(tabs_constants::kUrlKey, url_.spec()); | 103 changed_properties->Set(tabs_constants::kUrlKey, url_.spec()); |
92 } | 104 } |
93 | 105 |
94 return changed_properties; | 106 return changed_properties; |
95 } | 107 } |
96 | 108 |
109 bool TabsEventRouter::TabEntry::SetAudible(bool new_val) { | |
110 if (was_audible_ == new_val) | |
111 return false; | |
112 was_audible_ = new_val; | |
113 return true; | |
114 } | |
115 | |
116 bool TabsEventRouter::TabEntry::SetMuted(bool new_val) { | |
117 if (was_muted_ == new_val) | |
118 return false; | |
119 was_muted_ = new_val; | |
120 return true; | |
121 } | |
122 | |
97 TabsEventRouter::TabsEventRouter(Profile* profile) : profile_(profile) { | 123 TabsEventRouter::TabsEventRouter(Profile* profile) : profile_(profile) { |
98 DCHECK(!profile->IsOffTheRecord()); | 124 DCHECK(!profile->IsOffTheRecord()); |
99 | 125 |
100 BrowserList::AddObserver(this); | 126 BrowserList::AddObserver(this); |
101 | 127 |
102 // Init() can happen after the browser is running, so catch up with any | 128 // Init() can happen after the browser is running, so catch up with any |
103 // windows that already exist. | 129 // windows that already exist. |
104 for (chrome::BrowserIterator it; !it.done(); it.Next()) { | 130 for (chrome::BrowserIterator it; !it.done(); it.Next()) { |
105 RegisterForBrowserNotifications(*it); | 131 RegisterForBrowserNotifications(*it); |
106 | 132 |
107 // Also catch up our internal bookkeeping of tab entries. | 133 // Also catch up our internal bookkeeping of tab entries. |
108 Browser* browser = *it; | 134 Browser* browser = *it; |
109 if (browser->tab_strip_model()) { | 135 if (browser->tab_strip_model()) { |
110 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { | 136 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { |
111 WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(i); | 137 WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(i); |
112 int tab_id = ExtensionTabUtil::GetTabId(contents); | 138 int tab_id = ExtensionTabUtil::GetTabId(contents); |
113 tab_entries_[tab_id] = TabEntry(); | 139 tab_entries_[tab_id] = TabEntry(contents); |
114 } | 140 } |
115 } | 141 } |
116 } | 142 } |
117 } | 143 } |
118 | 144 |
119 TabsEventRouter::~TabsEventRouter() { | 145 TabsEventRouter::~TabsEventRouter() { |
120 BrowserList::RemoveObserver(this); | 146 BrowserList::RemoveObserver(this); |
121 } | 147 } |
122 | 148 |
123 void TabsEventRouter::OnBrowserAdded(Browser* browser) { | 149 void TabsEventRouter::OnBrowserAdded(Browser* browser) { |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
208 | 234 |
209 RegisterForTabNotifications(contents); | 235 RegisterForTabNotifications(contents); |
210 } | 236 } |
211 | 237 |
212 void TabsEventRouter::TabInsertedAt(WebContents* contents, | 238 void TabsEventRouter::TabInsertedAt(WebContents* contents, |
213 int index, | 239 int index, |
214 bool active) { | 240 bool active) { |
215 // If tab is new, send created event. | 241 // If tab is new, send created event. |
216 int tab_id = ExtensionTabUtil::GetTabId(contents); | 242 int tab_id = ExtensionTabUtil::GetTabId(contents); |
217 if (!GetTabEntry(contents)) { | 243 if (!GetTabEntry(contents)) { |
218 tab_entries_[tab_id] = TabEntry(); | 244 tab_entries_[tab_id] = TabEntry(contents); |
219 | 245 |
220 TabCreatedAt(contents, index, active); | 246 TabCreatedAt(contents, index, active); |
221 return; | 247 return; |
222 } | 248 } |
223 | 249 |
224 scoped_ptr<base::ListValue> args(new base::ListValue); | 250 scoped_ptr<base::ListValue> args(new base::ListValue); |
225 args->Append(new FundamentalValue(tab_id)); | 251 args->Append(new FundamentalValue(tab_id)); |
226 | 252 |
227 base::DictionaryValue* object_args = new base::DictionaryValue(); | 253 base::DictionaryValue* object_args = new base::DictionaryValue(); |
228 object_args->Set(tabs_constants::kNewWindowIdKey, | 254 object_args->Set(tabs_constants::kNewWindowIdKey, |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
383 new FundamentalValue(to_index)); | 409 new FundamentalValue(to_index)); |
384 args->Append(object_args); | 410 args->Append(object_args); |
385 | 411 |
386 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); | 412 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); |
387 DispatchEvent(profile, | 413 DispatchEvent(profile, |
388 tabs::OnMoved::kEventName, | 414 tabs::OnMoved::kEventName, |
389 args.Pass(), | 415 args.Pass(), |
390 EventRouter::USER_GESTURE_UNKNOWN); | 416 EventRouter::USER_GESTURE_UNKNOWN); |
391 } | 417 } |
392 | 418 |
393 void TabsEventRouter::TabUpdated(WebContents* contents, bool did_navigate) { | 419 void TabsEventRouter::TabUpdated(TabsEventRouter::TabEntry* entry, |
394 TabEntry* entry = GetTabEntry(contents); | 420 DictionaryBuilder* changed_properties) { |
not at google - send to devlin
2015/03/16 18:11:55
Yeah, I think that passing a DictionaryValue in he
| |
395 scoped_ptr<base::DictionaryValue> changed_properties; | 421 CHECK(entry->contents_); |
396 | 422 |
397 CHECK(entry); | 423 bool audible = entry->contents_->WasRecentlyAudible(); |
424 if (entry->SetAudible(audible)) { | |
425 changed_properties->SetBoolean(tabs_constants::kAudibleKey, audible); | |
426 } | |
398 | 427 |
399 if (did_navigate) | 428 bool muted = entry->contents_->IsAudioMuted(); |
400 changed_properties.reset(entry->DidNavigate(contents)); | 429 if (entry->SetMuted(muted)) { |
401 else | 430 changed_properties->SetBoolean(tabs_constants::kMutedKey, muted); |
402 changed_properties.reset(entry->UpdateLoadState(contents)); | 431 changed_properties->Set(tabs_constants::kMutedCauseKey, |
432 chrome::GetTabAudioMutedCause(entry->contents_)); | |
433 } | |
403 | 434 |
404 if (changed_properties) | 435 if (changed_properties->size() > 0) { |
not at google - send to devlin
2015/03/16 18:11:55
use .empty() preferably.
| |
405 DispatchTabUpdatedEvent(contents, changed_properties.Pass()); | 436 DispatchTabUpdatedEvent(entry->contents_, changed_properties->Build()); |
437 } | |
406 } | 438 } |
407 | 439 |
408 void TabsEventRouter::FaviconUrlUpdated(WebContents* contents) { | 440 void TabsEventRouter::FaviconUrlUpdated(WebContents* contents) { |
409 content::NavigationEntry* entry = | 441 content::NavigationEntry* entry = |
410 contents->GetController().GetVisibleEntry(); | 442 contents->GetController().GetVisibleEntry(); |
411 if (!entry || !entry->GetFavicon().valid) | 443 if (!entry || !entry->GetFavicon().valid) |
412 return; | 444 return; |
413 scoped_ptr<base::DictionaryValue> changed_properties( | 445 scoped_ptr<base::DictionaryValue> changed_properties( |
414 new base::DictionaryValue); | 446 new base::DictionaryValue); |
415 changed_properties->SetString( | 447 changed_properties->SetString( |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
486 return NULL; | 518 return NULL; |
487 return &i->second; | 519 return &i->second; |
488 } | 520 } |
489 | 521 |
490 void TabsEventRouter::Observe(int type, | 522 void TabsEventRouter::Observe(int type, |
491 const content::NotificationSource& source, | 523 const content::NotificationSource& source, |
492 const content::NotificationDetails& details) { | 524 const content::NotificationDetails& details) { |
493 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { | 525 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { |
494 NavigationController* source_controller = | 526 NavigationController* source_controller = |
495 content::Source<NavigationController>(source).ptr(); | 527 content::Source<NavigationController>(source).ptr(); |
496 TabUpdated(source_controller->GetWebContents(), true); | 528 TabEntry* entry = GetTabEntry(source_controller->GetWebContents()); |
529 CHECK(entry); | |
530 TabUpdated(entry, entry->DidNavigate()); | |
497 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { | 531 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { |
498 // Tab was destroyed after being detached (without being re-attached). | 532 // Tab was destroyed after being detached (without being re-attached). |
499 WebContents* contents = content::Source<WebContents>(source).ptr(); | 533 WebContents* contents = content::Source<WebContents>(source).ptr(); |
500 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | 534 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
501 content::Source<NavigationController>(&contents->GetController())); | 535 content::Source<NavigationController>(&contents->GetController())); |
502 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 536 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
503 content::Source<WebContents>(contents)); | 537 content::Source<WebContents>(contents)); |
504 registrar_.Remove(this, chrome::NOTIFICATION_FAVICON_UPDATED, | 538 registrar_.Remove(this, chrome::NOTIFICATION_FAVICON_UPDATED, |
505 content::Source<WebContents>(contents)); | 539 content::Source<WebContents>(contents)); |
506 } else if (type == chrome::NOTIFICATION_FAVICON_UPDATED) { | 540 } else if (type == chrome::NOTIFICATION_FAVICON_UPDATED) { |
507 bool icon_url_changed = *content::Details<bool>(details).ptr(); | 541 bool icon_url_changed = *content::Details<bool>(details).ptr(); |
508 if (icon_url_changed) | 542 if (icon_url_changed) |
509 FaviconUrlUpdated(content::Source<WebContents>(source).ptr()); | 543 FaviconUrlUpdated(content::Source<WebContents>(source).ptr()); |
510 } else { | 544 } else { |
511 NOTREACHED(); | 545 NOTREACHED(); |
512 } | 546 } |
513 } | 547 } |
514 | 548 |
515 void TabsEventRouter::TabChangedAt(WebContents* contents, | 549 void TabsEventRouter::TabChangedAt(WebContents* contents, |
516 int index, | 550 int index, |
517 TabChangeType change_type) { | 551 TabChangeType change_type) { |
518 TabUpdated(contents, false); | 552 TabEntry* entry = GetTabEntry(contents); |
553 CHECK(entry); | |
554 TabUpdated(entry, entry->UpdateLoadState()); | |
519 } | 555 } |
520 | 556 |
521 void TabsEventRouter::TabReplacedAt(TabStripModel* tab_strip_model, | 557 void TabsEventRouter::TabReplacedAt(TabStripModel* tab_strip_model, |
522 WebContents* old_contents, | 558 WebContents* old_contents, |
523 WebContents* new_contents, | 559 WebContents* new_contents, |
524 int index) { | 560 int index) { |
525 // Notify listeners that the next tabs closing or being added are due to | 561 // Notify listeners that the next tabs closing or being added are due to |
526 // WebContents being swapped. | 562 // WebContents being swapped. |
527 const int new_tab_id = ExtensionTabUtil::GetTabId(new_contents); | 563 const int new_tab_id = ExtensionTabUtil::GetTabId(new_contents); |
528 const int old_tab_id = ExtensionTabUtil::GetTabId(old_contents); | 564 const int old_tab_id = ExtensionTabUtil::GetTabId(old_contents); |
529 scoped_ptr<base::ListValue> args(new base::ListValue); | 565 scoped_ptr<base::ListValue> args(new base::ListValue); |
530 args->Append(new FundamentalValue(new_tab_id)); | 566 args->Append(new FundamentalValue(new_tab_id)); |
531 args->Append(new FundamentalValue(old_tab_id)); | 567 args->Append(new FundamentalValue(old_tab_id)); |
532 | 568 |
533 DispatchEvent(Profile::FromBrowserContext(new_contents->GetBrowserContext()), | 569 DispatchEvent(Profile::FromBrowserContext(new_contents->GetBrowserContext()), |
534 tabs::OnReplaced::kEventName, | 570 tabs::OnReplaced::kEventName, |
535 args.Pass(), | 571 args.Pass(), |
536 EventRouter::USER_GESTURE_UNKNOWN); | 572 EventRouter::USER_GESTURE_UNKNOWN); |
537 | 573 |
538 // Update tab_entries_. | 574 // Update tab_entries_. |
539 const int removed_count = tab_entries_.erase(old_tab_id); | 575 const int removed_count = tab_entries_.erase(old_tab_id); |
540 DCHECK_GT(removed_count, 0); | 576 DCHECK_GT(removed_count, 0); |
541 UnregisterForTabNotifications(old_contents); | 577 UnregisterForTabNotifications(old_contents); |
542 | 578 |
543 if (!GetTabEntry(new_contents)) { | 579 if (!GetTabEntry(new_contents)) { |
544 tab_entries_[new_tab_id] = TabEntry(); | 580 tab_entries_[new_tab_id] = TabEntry(new_contents); |
545 RegisterForTabNotifications(new_contents); | 581 RegisterForTabNotifications(new_contents); |
546 } | 582 } |
547 } | 583 } |
548 | 584 |
549 void TabsEventRouter::TabPinnedStateChanged(WebContents* contents, int index) { | 585 void TabsEventRouter::TabPinnedStateChanged(WebContents* contents, int index) { |
550 TabStripModel* tab_strip = NULL; | 586 TabStripModel* tab_strip = NULL; |
551 int tab_index; | 587 int tab_index; |
552 | 588 |
553 if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index)) { | 589 if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index)) { |
554 scoped_ptr<base::DictionaryValue> changed_properties( | 590 scoped_ptr<base::DictionaryValue> changed_properties( |
(...skipping 24 matching lines...) Expand all Loading... | |
579 // Dispatch the |onZoomChange| event. | 615 // Dispatch the |onZoomChange| event. |
580 Profile* profile = Profile::FromBrowserContext( | 616 Profile* profile = Profile::FromBrowserContext( |
581 data.web_contents->GetBrowserContext()); | 617 data.web_contents->GetBrowserContext()); |
582 DispatchEvent(profile, | 618 DispatchEvent(profile, |
583 tabs::OnZoomChange::kEventName, | 619 tabs::OnZoomChange::kEventName, |
584 api::tabs::OnZoomChange::Create(zoom_change_info), | 620 api::tabs::OnZoomChange::Create(zoom_change_info), |
585 EventRouter::USER_GESTURE_UNKNOWN); | 621 EventRouter::USER_GESTURE_UNKNOWN); |
586 } | 622 } |
587 | 623 |
588 } // namespace extensions | 624 } // namespace extensions |
OLD | NEW |