| 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/extensions/extension_toolbar_model.h" | 5 #include "chrome/browser/extensions/extension_toolbar_model.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/metrics/histogram_base.h" | 12 #include "base/metrics/histogram_base.h" |
| 13 #include "base/prefs/pref_service.h" | 13 #include "base/prefs/pref_service.h" |
| 14 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
| 15 #include "base/thread_task_runner_handle.h" | 15 #include "base/thread_task_runner_handle.h" |
| 16 #include "chrome/browser/chrome_notification_types.h" | 16 #include "chrome/browser/chrome_notification_types.h" |
| 17 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" | 17 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" |
| 18 #include "chrome/browser/extensions/extension_action_manager.h" | 18 #include "chrome/browser/extensions/extension_action_manager.h" |
| 19 #include "chrome/browser/extensions/extension_tab_util.h" | 19 #include "chrome/browser/extensions/extension_tab_util.h" |
| 20 #include "chrome/browser/extensions/extension_toolbar_model_factory.h" | 20 #include "chrome/browser/extensions/extension_toolbar_model_factory.h" |
| 21 #include "chrome/browser/extensions/extension_util.h" | 21 #include "chrome/browser/extensions/extension_util.h" |
| 22 #include "chrome/browser/extensions/tab_helper.h" | 22 #include "chrome/browser/extensions/tab_helper.h" |
| 23 #include "chrome/browser/profiles/profile.h" | 23 #include "chrome/browser/profiles/profile.h" |
| 24 #include "chrome/browser/ui/browser.h" | 24 #include "chrome/browser/ui/browser.h" |
| 25 #include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_d
elegate.h" |
| 25 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 26 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 26 #include "content/public/browser/notification_details.h" | 27 #include "content/public/browser/notification_details.h" |
| 27 #include "content/public/browser/notification_source.h" | 28 #include "content/public/browser/notification_source.h" |
| 28 #include "content/public/browser/web_contents.h" | 29 #include "content/public/browser/web_contents.h" |
| 29 #include "extensions/browser/extension_prefs.h" | 30 #include "extensions/browser/extension_prefs.h" |
| 30 #include "extensions/browser/extension_registry.h" | 31 #include "extensions/browser/extension_registry.h" |
| 31 #include "extensions/browser/extension_system.h" | 32 #include "extensions/browser/extension_system.h" |
| 32 #include "extensions/browser/pref_names.h" | 33 #include "extensions/browser/pref_names.h" |
| 33 #include "extensions/common/extension.h" | 34 #include "extensions/common/extension.h" |
| 34 #include "extensions/common/extension_set.h" | 35 #include "extensions/common/extension_set.h" |
| 35 #include "extensions/common/feature_switch.h" | 36 #include "extensions/common/feature_switch.h" |
| 36 #include "extensions/common/manifest_constants.h" | 37 #include "extensions/common/manifest_constants.h" |
| 37 #include "extensions/common/one_shot_event.h" | 38 #include "extensions/common/one_shot_event.h" |
| 38 | 39 |
| 39 namespace extensions { | 40 namespace extensions { |
| 40 | 41 |
| 41 ExtensionToolbarModel::ExtensionToolbarModel(Profile* profile, | 42 ExtensionToolbarModel::ExtensionToolbarModel(Profile* profile, |
| 42 ExtensionPrefs* extension_prefs) | 43 ExtensionPrefs* extension_prefs) |
| 43 : profile_(profile), | 44 : profile_(profile), |
| 44 extension_prefs_(extension_prefs), | 45 extension_prefs_(extension_prefs), |
| 45 prefs_(profile_->GetPrefs()), | 46 prefs_(profile_->GetPrefs()), |
| 46 extension_action_api_(ExtensionActionAPI::Get(profile_)), | 47 extension_action_api_(ExtensionActionAPI::Get(profile_)), |
| 47 extensions_initialized_(false), | 48 extensions_initialized_(false), |
| 48 include_all_extensions_( | 49 include_all_extensions_(FeatureSwitch::extension_action_redesign() |
| 49 FeatureSwitch::extension_action_redesign()->IsEnabled()), | 50 ->IsEnabled()), |
| 50 is_highlighting_(false), | 51 highlight_type_(HIGHLIGHT_NONE), |
| 51 extension_action_observer_(this), | 52 extension_action_observer_(this), |
| 52 extension_registry_observer_(this), | 53 extension_registry_observer_(this), |
| 53 weak_ptr_factory_(this) { | 54 weak_ptr_factory_(this) { |
| 54 ExtensionSystem::Get(profile_)->ready().Post( | 55 ExtensionSystem::Get(profile_)->ready().Post( |
| 55 FROM_HERE, | 56 FROM_HERE, |
| 56 base::Bind(&ExtensionToolbarModel::OnReady, | 57 base::Bind(&ExtensionToolbarModel::OnReady, |
| 57 weak_ptr_factory_.GetWeakPtr())); | 58 weak_ptr_factory_.GetWeakPtr())); |
| 58 visible_icon_count_ = prefs_->GetInteger(pref_names::kToolbarSize); | 59 visible_icon_count_ = prefs_->GetInteger(pref_names::kToolbarSize); |
| 59 | 60 |
| 60 // We only care about watching the prefs if not in incognito mode. | 61 // We only care about watching the prefs if not in incognito mode. |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 UpdatePrefs(); | 126 UpdatePrefs(); |
| 126 } | 127 } |
| 127 | 128 |
| 128 void ExtensionToolbarModel::SetVisibleIconCount(size_t count) { | 129 void ExtensionToolbarModel::SetVisibleIconCount(size_t count) { |
| 129 visible_icon_count_ = (count >= toolbar_items_.size()) ? -1 : count; | 130 visible_icon_count_ = (count >= toolbar_items_.size()) ? -1 : count; |
| 130 | 131 |
| 131 // Only set the prefs if we're not in highlight mode and the profile is not | 132 // Only set the prefs if we're not in highlight mode and the profile is not |
| 132 // incognito. Highlight mode is designed to be a transitory state, and should | 133 // incognito. Highlight mode is designed to be a transitory state, and should |
| 133 // not persist across browser restarts (though it may be re-entered), and we | 134 // not persist across browser restarts (though it may be re-entered), and we |
| 134 // don't store anything in incognito. | 135 // don't store anything in incognito. |
| 135 if (!is_highlighting_ && !profile_->IsOffTheRecord()) { | 136 if (!is_highlighting() && !profile_->IsOffTheRecord()) { |
| 136 // Additionally, if we are using the new toolbar, any icons which are in the | 137 // Additionally, if we are using the new toolbar, any icons which are in the |
| 137 // overflow menu are considered "hidden". But it so happens that the times | 138 // overflow menu are considered "hidden". But it so happens that the times |
| 138 // we are likely to call SetVisibleIconCount() are also those when we are | 139 // we are likely to call SetVisibleIconCount() are also those when we are |
| 139 // in flux. So wait for things to cool down before setting the prefs. | 140 // in flux. So wait for things to cool down before setting the prefs. |
| 140 base::ThreadTaskRunnerHandle::Get()->PostTask( | 141 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 141 FROM_HERE, | 142 FROM_HERE, |
| 142 base::Bind(&ExtensionToolbarModel::MaybeUpdateVisibilityPrefs, | 143 base::Bind(&ExtensionToolbarModel::MaybeUpdateVisibilityPrefs, |
| 143 weak_ptr_factory_.GetWeakPtr())); | 144 weak_ptr_factory_.GetWeakPtr())); |
| 144 prefs_->SetInteger(pref_names::kToolbarSize, visible_icon_count_); | 145 prefs_->SetInteger(pref_names::kToolbarSize, visible_icon_count_); |
| 145 } | 146 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 } | 242 } |
| 242 | 243 |
| 243 void ExtensionToolbarModel::OnReady() { | 244 void ExtensionToolbarModel::OnReady() { |
| 244 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); | 245 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); |
| 245 InitializeExtensionList(); | 246 InitializeExtensionList(); |
| 246 // Wait until the extension system is ready before observing any further | 247 // Wait until the extension system is ready before observing any further |
| 247 // changes so that the toolbar buttons can be shown in their stable ordering | 248 // changes so that the toolbar buttons can be shown in their stable ordering |
| 248 // taken from prefs. | 249 // taken from prefs. |
| 249 extension_registry_observer_.Add(registry); | 250 extension_registry_observer_.Add(registry); |
| 250 extension_action_observer_.Add(extension_action_api_); | 251 extension_action_observer_.Add(extension_action_api_); |
| 252 |
| 253 if (ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile( |
| 254 profile_)) { |
| 255 ExtensionIdList ids; |
| 256 for (const auto& extension : toolbar_items_) |
| 257 ids.push_back(extension->id()); |
| 258 HighlightExtensions(ids, HIGHLIGHT_INFO); |
| 259 } |
| 260 |
| 261 extensions_initialized_ = true; |
| 262 FOR_EACH_OBSERVER(Observer, observers_, OnToolbarModelInitialized()); |
| 251 } | 263 } |
| 252 | 264 |
| 253 size_t ExtensionToolbarModel::FindNewPositionFromLastKnownGood( | 265 size_t ExtensionToolbarModel::FindNewPositionFromLastKnownGood( |
| 254 const Extension* extension) { | 266 const Extension* extension) { |
| 255 // See if we have last known good position for this extension. | 267 // See if we have last known good position for this extension. |
| 256 size_t new_index = 0; | 268 size_t new_index = 0; |
| 257 // Loop through the ID list of known positions, to count the number of visible | 269 // Loop through the ID list of known positions, to count the number of visible |
| 258 // extension icons preceding |extension|. | 270 // extension icons preceding |extension|. |
| 259 for (ExtensionIdList::const_iterator iter_id = last_known_positions_.begin(); | 271 for (ExtensionIdList::const_iterator iter_id = last_known_positions_.begin(); |
| 260 iter_id < last_known_positions_.end(); ++iter_id) { | 272 iter_id < last_known_positions_.end(); ++iter_id) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 UpdatePrefs(); | 346 UpdatePrefs(); |
| 335 } else { | 347 } else { |
| 336 new_index = FindNewPositionFromLastKnownGood(extension); | 348 new_index = FindNewPositionFromLastKnownGood(extension); |
| 337 } | 349 } |
| 338 | 350 |
| 339 toolbar_items_.insert(toolbar_items_.begin() + new_index, extension); | 351 toolbar_items_.insert(toolbar_items_.begin() + new_index, extension); |
| 340 | 352 |
| 341 // If we're currently highlighting, then even though we add a browser action | 353 // If we're currently highlighting, then even though we add a browser action |
| 342 // to the full list (|toolbar_items_|, there won't be another *visible* | 354 // to the full list (|toolbar_items_|, there won't be another *visible* |
| 343 // browser action, which was what the observers care about. | 355 // browser action, which was what the observers care about. |
| 344 if (!is_highlighting_) { | 356 if (!is_highlighting()) { |
| 345 FOR_EACH_OBSERVER(Observer, observers_, | 357 FOR_EACH_OBSERVER(Observer, observers_, |
| 346 OnToolbarExtensionAdded(extension, new_index)); | 358 OnToolbarExtensionAdded(extension, new_index)); |
| 347 | 359 |
| 348 int visible_count_delta = 0; | 360 int visible_count_delta = 0; |
| 349 if (is_new_extension && !all_icons_visible()) { | 361 if (is_new_extension && !all_icons_visible()) { |
| 350 // If this is a new extension (and not all extensions are visible), we | 362 // If this is a new extension (and not all extensions are visible), we |
| 351 // expand the toolbar out so that the new one can be seen. | 363 // expand the toolbar out so that the new one can be seen. |
| 352 visible_count_delta = 1; | 364 visible_count_delta = 1; |
| 353 } else if (profile_->IsOffTheRecord()) { | 365 } else if (profile_->IsOffTheRecord()) { |
| 354 // If this is an incognito profile, we also have to check to make sure the | 366 // If this is an incognito profile, we also have to check to make sure the |
| (...skipping 29 matching lines...) Expand all Loading... |
| 384 return; | 396 return; |
| 385 | 397 |
| 386 // If our visible count is set to the current size, we need to decrement it. | 398 // If our visible count is set to the current size, we need to decrement it. |
| 387 if (visible_icon_count_ == static_cast<int>(toolbar_items_.size())) | 399 if (visible_icon_count_ == static_cast<int>(toolbar_items_.size())) |
| 388 SetVisibleIconCount(toolbar_items_.size() - 1); | 400 SetVisibleIconCount(toolbar_items_.size() - 1); |
| 389 | 401 |
| 390 toolbar_items_.erase(pos); | 402 toolbar_items_.erase(pos); |
| 391 | 403 |
| 392 // If we're in highlight mode, we also have to remove the extension from | 404 // If we're in highlight mode, we also have to remove the extension from |
| 393 // the highlighted list. | 405 // the highlighted list. |
| 394 if (is_highlighting_) { | 406 if (is_highlighting()) { |
| 395 pos = std::find(highlighted_items_.begin(), | 407 pos = std::find(highlighted_items_.begin(), |
| 396 highlighted_items_.end(), | 408 highlighted_items_.end(), |
| 397 extension); | 409 extension); |
| 398 if (pos != highlighted_items_.end()) { | 410 if (pos != highlighted_items_.end()) { |
| 399 highlighted_items_.erase(pos); | 411 highlighted_items_.erase(pos); |
| 400 FOR_EACH_OBSERVER(Observer, observers_, | 412 FOR_EACH_OBSERVER(Observer, observers_, |
| 401 OnToolbarExtensionRemoved(extension)); | 413 OnToolbarExtensionRemoved(extension)); |
| 402 // If the highlighted list is now empty, we stop highlighting. | 414 // If the highlighted list is now empty, we stop highlighting. |
| 403 if (highlighted_items_.empty()) | 415 if (highlighted_items_.empty()) |
| 404 StopHighlighting(); | 416 StopHighlighting(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 420 // 3. Remove holes from the sorted vector and append the unsorted vector. | 432 // 3. Remove holes from the sorted vector and append the unsorted vector. |
| 421 void ExtensionToolbarModel::InitializeExtensionList() { | 433 void ExtensionToolbarModel::InitializeExtensionList() { |
| 422 DCHECK(toolbar_items_.empty()); // We shouldn't have any items yet. | 434 DCHECK(toolbar_items_.empty()); // We shouldn't have any items yet. |
| 423 | 435 |
| 424 last_known_positions_ = extension_prefs_->GetToolbarOrder(); | 436 last_known_positions_ = extension_prefs_->GetToolbarOrder(); |
| 425 if (profile_->IsOffTheRecord()) | 437 if (profile_->IsOffTheRecord()) |
| 426 IncognitoPopulate(); | 438 IncognitoPopulate(); |
| 427 else | 439 else |
| 428 Populate(&last_known_positions_); | 440 Populate(&last_known_positions_); |
| 429 | 441 |
| 430 extensions_initialized_ = true; | |
| 431 MaybeUpdateVisibilityPrefs(); | 442 MaybeUpdateVisibilityPrefs(); |
| 432 FOR_EACH_OBSERVER(Observer, observers_, OnToolbarModelInitialized()); | |
| 433 } | 443 } |
| 434 | 444 |
| 435 void ExtensionToolbarModel::Populate(ExtensionIdList* positions) { | 445 void ExtensionToolbarModel::Populate(ExtensionIdList* positions) { |
| 436 DCHECK(!profile_->IsOffTheRecord()); | 446 DCHECK(!profile_->IsOffTheRecord()); |
| 437 const ExtensionSet& extensions = | 447 const ExtensionSet& extensions = |
| 438 ExtensionRegistry::Get(profile_)->enabled_extensions(); | 448 ExtensionRegistry::Get(profile_)->enabled_extensions(); |
| 439 // Items that have explicit positions. | 449 // Items that have explicit positions. |
| 440 ExtensionList sorted(positions->size(), NULL); | 450 ExtensionList sorted(positions->size(), NULL); |
| 441 // The items that don't have explicit positions. | 451 // The items that don't have explicit positions. |
| 442 ExtensionList unsorted; | 452 ExtensionList unsorted; |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 if (extension - toolbar_items_.begin() >= | 660 if (extension - toolbar_items_.begin() >= |
| 651 static_cast<int>(visible_icon_count())) | 661 static_cast<int>(visible_icon_count())) |
| 652 MoveExtensionIcon((*extension)->id(), 0); | 662 MoveExtensionIcon((*extension)->id(), 0); |
| 653 break; | 663 break; |
| 654 } | 664 } |
| 655 } | 665 } |
| 656 } | 666 } |
| 657 } | 667 } |
| 658 | 668 |
| 659 bool ExtensionToolbarModel::HighlightExtensions( | 669 bool ExtensionToolbarModel::HighlightExtensions( |
| 660 const ExtensionIdList& extension_ids) { | 670 const ExtensionIdList& extension_ids, |
| 671 HighlightType highlight_type) { |
| 661 highlighted_items_.clear(); | 672 highlighted_items_.clear(); |
| 662 | 673 |
| 663 for (ExtensionIdList::const_iterator id = extension_ids.begin(); | 674 for (ExtensionIdList::const_iterator id = extension_ids.begin(); |
| 664 id != extension_ids.end(); | 675 id != extension_ids.end(); |
| 665 ++id) { | 676 ++id) { |
| 666 for (ExtensionList::const_iterator extension = toolbar_items_.begin(); | 677 for (ExtensionList::const_iterator extension = toolbar_items_.begin(); |
| 667 extension != toolbar_items_.end(); | 678 extension != toolbar_items_.end(); |
| 668 ++extension) { | 679 ++extension) { |
| 669 if (*id == (*extension)->id()) | 680 if (*id == (*extension)->id()) |
| 670 highlighted_items_.push_back(*extension); | 681 highlighted_items_.push_back(*extension); |
| 671 } | 682 } |
| 672 } | 683 } |
| 673 | 684 |
| 674 // If we have any items in |highlighted_items_|, then we entered highlighting | 685 // If we have any items in |highlighted_items_|, then we entered highlighting |
| 675 // mode. | 686 // mode. |
| 676 if (highlighted_items_.size()) { | 687 if (highlighted_items_.size()) { |
| 677 old_visible_icon_count_ = visible_icon_count_; | 688 // It's important that is_highlighting_ is changed immediately before the |
| 689 // observers are notified since it changes the result of toolbar_items(). |
| 690 highlight_type_ = highlight_type; |
| 691 FOR_EACH_OBSERVER(Observer, observers_, |
| 692 OnToolbarHighlightModeChanged(true)); |
| 693 |
| 694 // We set the visible icon count after the highlight mode change because |
| 695 // the UI actions are created/destroyed during highlight, and doing that |
| 696 // prior to changing the size allows us to still have smooth animations. |
| 678 if (visible_icon_count() < extension_ids.size()) | 697 if (visible_icon_count() < extension_ids.size()) |
| 679 SetVisibleIconCount(extension_ids.size()); | 698 SetVisibleIconCount(extension_ids.size()); |
| 680 | 699 |
| 681 // It's important that is_highlighting_ is changed immediately before the | |
| 682 // observers are notified since it changes the result of toolbar_items(). | |
| 683 is_highlighting_ = true; | |
| 684 FOR_EACH_OBSERVER(Observer, observers_, | |
| 685 OnToolbarHighlightModeChanged(true)); | |
| 686 return true; | 700 return true; |
| 687 } | 701 } |
| 688 | 702 |
| 689 // Otherwise, we didn't enter highlighting mode (and, in fact, exited it if | 703 // Otherwise, we didn't enter highlighting mode (and, in fact, exited it if |
| 690 // we were otherwise in it). | 704 // we were otherwise in it). |
| 691 if (is_highlighting_) | 705 if (is_highlighting()) |
| 692 StopHighlighting(); | 706 StopHighlighting(); |
| 693 return false; | 707 return false; |
| 694 } | 708 } |
| 695 | 709 |
| 696 void ExtensionToolbarModel::StopHighlighting() { | 710 void ExtensionToolbarModel::StopHighlighting() { |
| 697 if (is_highlighting_) { | 711 if (is_highlighting()) { |
| 698 if (old_visible_icon_count_ != visible_icon_count_) | |
| 699 SetVisibleIconCount(old_visible_icon_count_); | |
| 700 | |
| 701 // It's important that is_highlighting_ is changed immediately before the | 712 // It's important that is_highlighting_ is changed immediately before the |
| 702 // observers are notified since it changes the result of toolbar_items(). | 713 // observers are notified since it changes the result of toolbar_items(). |
| 703 is_highlighting_ = false; | 714 highlight_type_ = HIGHLIGHT_NONE; |
| 704 FOR_EACH_OBSERVER(Observer, observers_, | 715 FOR_EACH_OBSERVER(Observer, observers_, |
| 705 OnToolbarHighlightModeChanged(false)); | 716 OnToolbarHighlightModeChanged(false)); |
| 717 |
| 706 // For the same reason, we don't clear highlighted_items_ until after the | 718 // For the same reason, we don't clear highlighted_items_ until after the |
| 707 // mode changed. | 719 // mode changed. |
| 708 highlighted_items_.clear(); | 720 highlighted_items_.clear(); |
| 721 |
| 722 // We set the visible icon count after the highlight mode change because |
| 723 // the UI actions are created/destroyed during highlight, and doing that |
| 724 // prior to changing the size allows us to still have smooth animations. |
| 725 int saved_icon_count = prefs_->GetInteger(pref_names::kToolbarSize); |
| 726 if (saved_icon_count != visible_icon_count_) |
| 727 SetVisibleIconCount(saved_icon_count); |
| 709 } | 728 } |
| 710 } | 729 } |
| 711 | 730 |
| 712 bool ExtensionToolbarModel::RedesignIsShowingNewIcons() const { | 731 bool ExtensionToolbarModel::RedesignIsShowingNewIcons() const { |
| 713 for (const scoped_refptr<const Extension>& extension : toolbar_items_) { | 732 for (const scoped_refptr<const Extension>& extension : toolbar_items_) { |
| 714 // Without the redesign, we only show extensions with browser actions. | 733 // Without the redesign, we only show extensions with browser actions. |
| 715 // Any extension without a browser action is an indication that we're | 734 // Any extension without a browser action is an indication that we're |
| 716 // showing something new. | 735 // showing something new. |
| 717 if (!extension->manifest()->HasKey(manifest_keys::kBrowserAction)) | 736 if (!extension->manifest()->HasKey(manifest_keys::kBrowserAction)) |
| 718 return true; | 737 return true; |
| 719 } | 738 } |
| 720 return false; | 739 return false; |
| 721 } | 740 } |
| 722 | 741 |
| 723 } // namespace extensions | 742 } // namespace extensions |
| OLD | NEW |