1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/chrome_app_sorting.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_scoped_prefs.h" 121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/extensions/extension_sync_service.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/common/extensions/extension_constants.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/extensions/default_app_order.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace extensions { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of apps per page. This isn't a hard limit, but new apps installed 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from the webstore will overflow onto a new page if this limit is reached. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kNaturalAppPageSize = 18; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A preference determining the order of which the apps appear on the NTP. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPrefAppLaunchIndexDeprecated[] = "app_launcher_index"; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPrefAppLaunchOrdinal[] = "app_launcher_ordinal"; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A preference determining the page on which an app appears in the NTP. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPrefPageIndexDeprecated[] = "page_index"; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPrefPageOrdinal[] = "page_ordinal"; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// ChromeAppSorting::AppOrdinals 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ChromeAppSorting::AppOrdinals::AppOrdinals() {} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ChromeAppSorting::AppOrdinals::~AppOrdinals() {} 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//////////////////////////////////////////////////////////////////////////////// 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// ChromeAppSorting 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ChromeAppSorting::ChromeAppSorting() 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : extension_scoped_prefs_(NULL), 511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) extension_sync_service_(NULL), 5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) default_ordinals_created_(false) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ChromeAppSorting::~ChromeAppSorting() { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::SetExtensionScopedPrefs(ExtensionScopedPrefs* prefs) { 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) extension_scoped_prefs_ = prefs; 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::SetExtensionSyncService( 631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ExtensionSyncService* extension_sync_service) { 641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) extension_sync_service_ = extension_sync_service; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::Initialize( 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::ExtensionIdList& extension_ids) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializePageOrdinalMap(extension_ids); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MigrateAppIndex(extension_ids); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::CreateOrdinalsIfNecessary(size_t minimum_size) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create StringOrdinal values as required to ensure |ntp_ordinal_map_| has at 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // least |minimum_size| entries. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ntp_ordinal_map_.empty() && minimum_size > 0) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ntp_ordinal_map_[syncer::StringOrdinal::CreateInitialOrdinal()]; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ntp_ordinal_map_.size() < minimum_size) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal filler = 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ntp_ordinal_map_.rbegin()->first.CreateAfter(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppLaunchOrdinalMap empty_ordinal_map; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ntp_ordinal_map_.insert(std::make_pair(filler, empty_ordinal_map)); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::MigrateAppIndex( 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::ExtensionIdList& extension_ids) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (extension_ids.empty()) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert all the page index values to page ordinals. If there are any 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // app launch values that need to be migrated, inserted them into a sorted 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // set to be dealt with later. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::map<syncer::StringOrdinal, std::map<int, const std::string*>, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal::LessThanFn> AppPositionToIdMapping; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppPositionToIdMapping app_launches_to_convert; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (extensions::ExtensionIdList::const_iterator ext_id = 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_ids.begin(); ext_id != extension_ids.end(); ++ext_id) { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_page_index = 0; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal page = GetPageOrdinal(*ext_id); 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (extension_scoped_prefs_->ReadPrefAsInteger( 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ext_id, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPrefPageIndexDeprecated, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &old_page_index)) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some extensions have invalid page index, so we don't 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // attempt to convert them. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (old_page_index < 0) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Extension " << *ext_id 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " has an invalid page index " << old_page_index 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << ". Aborting attempt to convert its index."; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateOrdinalsIfNecessary(static_cast<size_t>(old_page_index) + 1); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page = PageIntegerAsStringOrdinal(old_page_index); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetPageOrdinal(*ext_id, page); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_scoped_prefs_->UpdateExtensionPref( 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ext_id, kPrefPageIndexDeprecated, NULL); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_app_launch_index = 0; 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (extension_scoped_prefs_->ReadPrefAsInteger( 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ext_id, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPrefAppLaunchIndexDeprecated, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &old_app_launch_index)) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can't update the app launch index value yet, because we use 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GetNextAppLaunchOrdinal to get the new ordinal value and it requires 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // all the ordinals with lower values to have already been migrated. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A valid page ordinal is also required because otherwise there is 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // no page to add the app to. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page.IsValid()) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_launches_to_convert[page][old_app_launch_index] = &*ext_id; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_scoped_prefs_->UpdateExtensionPref( 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ext_id, kPrefAppLaunchIndexDeprecated, NULL); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove any empty pages that may have been added. This shouldn't occur, 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but double check here to prevent future problems with conversions between 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // integers and StringOrdinals. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PageOrdinalMap::iterator it = ntp_ordinal_map_.begin(); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != ntp_ordinal_map_.end();) { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->second.empty()) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PageOrdinalMap::iterator prev_it = it; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ntp_ordinal_map_.erase(prev_it); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (app_launches_to_convert.empty()) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the new app launch ordinals and remove the old preferences. Since 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the set is sorted, each time we migrate an apps index, we know that all of 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the remaining apps will appear further down the NTP than it or on a 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // different page. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (AppPositionToIdMapping::const_iterator page_it = 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_launches_to_convert.begin(); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_it != app_launches_to_convert.end(); ++page_it) { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal page = page_it->first; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::map<int, const std::string*>::const_iterator launch_it = 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_it->second.begin(); launch_it != page_it->second.end(); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++launch_it) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetAppLaunchOrdinal(*(launch_it->second), 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateNextAppLaunchOrdinal(page)); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::FixNTPOrdinalCollisions() { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PageOrdinalMap::iterator page_it = ntp_ordinal_map_.begin(); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_it != ntp_ordinal_map_.end(); ++page_it) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppLaunchOrdinalMap& page = page_it->second; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppLaunchOrdinalMap::iterator app_launch_it = page.begin(); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (app_launch_it != page.end()) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int app_count = page.count(app_launch_it->first); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (app_count == 1) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++app_launch_it; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal repeated_ordinal = app_launch_it->first; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sort the conflicting keys by their extension id, this is how 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the order is decided. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> conflicting_ids; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < app_count; ++i, ++app_launch_it) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conflicting_ids.push_back(app_launch_it->second); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::sort(conflicting_ids.begin(), conflicting_ids.end()); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal upper_bound_ordinal = app_launch_it == page.end() ? 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal() : 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_launch_it->first; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal lower_bound_ordinal = repeated_ordinal; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start at position 1 because the first extension can keep the conflicted 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // value. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 1; i < app_count; ++i) { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal unique_app_launch; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (upper_bound_ordinal.IsValid()) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unique_app_launch = 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lower_bound_ordinal.CreateBetween(upper_bound_ordinal); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unique_app_launch = lower_bound_ordinal.CreateAfter(); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetAppLaunchOrdinal(conflicting_ids[i], unique_app_launch); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lower_bound_ordinal = unique_app_launch; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::current()->Notify( 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED, 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) content::Source<ChromeAppSorting>(this), 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::NoDetails()); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::EnsureValidOrdinals( 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& suggested_page) { 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal page_ordinal = GetPageOrdinal(extension_id); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!page_ordinal.IsValid()) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggested_page.IsValid()) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_ordinal = suggested_page; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!GetDefaultOrdinals(extension_id, &page_ordinal, NULL) || 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !page_ordinal.IsValid()) { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_ordinal = GetNaturalAppPageOrdinal(); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetPageOrdinal(extension_id, page_ordinal); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal app_launch_ordinal = GetAppLaunchOrdinal(extension_id); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!app_launch_ordinal.IsValid()) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If using default app launcher ordinal, make sure there is no collision. 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetDefaultOrdinals(extension_id, NULL, &app_launch_ordinal) && 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_launch_ordinal.IsValid()) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_launch_ordinal = ResolveCollision(page_ordinal, app_launch_ordinal); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_launch_ordinal = CreateNextAppLaunchOrdinal(page_ordinal); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetAppLaunchOrdinal(extension_id, app_launch_ordinal); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::OnExtensionMoved( 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& moved_extension_id, 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& predecessor_extension_id, 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& successor_extension_id) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We only need to change the StringOrdinal if there are neighbours. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!predecessor_extension_id.empty() || !successor_extension_id.empty()) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (predecessor_extension_id.empty()) { 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only a successor. 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetAppLaunchOrdinal( 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) moved_extension_id, 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAppLaunchOrdinal(successor_extension_id).CreateBefore()); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (successor_extension_id.empty()) { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only a predecessor. 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetAppLaunchOrdinal( 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) moved_extension_id, 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAppLaunchOrdinal(predecessor_extension_id).CreateAfter()); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Both a successor and predecessor 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& predecessor_ordinal = 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAppLaunchOrdinal(predecessor_extension_id); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& successor_ordinal = 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAppLaunchOrdinal(successor_extension_id); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetAppLaunchOrdinal(moved_extension_id, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) predecessor_ordinal.CreateBetween(successor_ordinal)); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::current()->Notify( 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED, 283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) content::Source<ChromeAppSorting>(this), 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details<const std::string>(&moved_extension_id)); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::GetAppLaunchOrdinal( 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id) const { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string raw_value; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the preference read fails then raw_value will still be unset and we 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will return an invalid StringOrdinal to signal that no app launch ordinal 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // was found. 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension_scoped_prefs_->ReadPrefAsString( 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, kPrefAppLaunchOrdinal, &raw_value); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return syncer::StringOrdinal(raw_value); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::SetAppLaunchOrdinal( 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& new_app_launch_ordinal) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No work is required if the old and new values are the same. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_app_launch_ordinal.EqualsOrBothInvalid( 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAppLaunchOrdinal(extension_id))) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal page_ordinal = GetPageOrdinal(extension_id); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveOrdinalMapping( 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, page_ordinal, GetAppLaunchOrdinal(extension_id)); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddOrdinalMapping(extension_id, page_ordinal, new_app_launch_ordinal); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Value* new_value = new_app_launch_ordinal.IsValid() ? 3143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) new base::StringValue(new_app_launch_ordinal.ToInternalValue()) : 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_scoped_prefs_->UpdateExtensionPref( 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPrefAppLaunchOrdinal, 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_value); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SyncIfNeeded(extension_id); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::CreateFirstAppLaunchOrdinal( 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& page_ordinal) const { 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& min_ordinal = 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetMinOrMaxAppLaunchOrdinalsOnPage(page_ordinal, 328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ChromeAppSorting::MIN_ORDINAL); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (min_ordinal.IsValid()) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return min_ordinal.CreateBefore(); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return syncer::StringOrdinal::CreateInitialOrdinal(); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::CreateNextAppLaunchOrdinal( 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& page_ordinal) const { 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& max_ordinal = 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetMinOrMaxAppLaunchOrdinalsOnPage(page_ordinal, 340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ChromeAppSorting::MAX_ORDINAL); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (max_ordinal.IsValid()) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return max_ordinal.CreateAfter(); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return syncer::StringOrdinal::CreateInitialOrdinal(); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::CreateFirstAppPageOrdinal() const { 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ntp_ordinal_map_.empty()) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return syncer::StringOrdinal::CreateInitialOrdinal(); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ntp_ordinal_map_.begin()->first; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::GetNaturalAppPageOrdinal() const { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ntp_ordinal_map_.empty()) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return syncer::StringOrdinal::CreateInitialOrdinal(); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PageOrdinalMap::const_iterator it = ntp_ordinal_map_.begin(); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != ntp_ordinal_map_.end(); ++it) { 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (CountItemsVisibleOnNtp(it->second) < kNaturalAppPageSize) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return it->first; 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add a new page as all existing pages are full. 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal last_element = ntp_ordinal_map_.rbegin()->first; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return last_element.CreateAfter(); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::GetPageOrdinal( 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id) const { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string raw_data; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the preference read fails then raw_data will still be unset and we will 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // return an invalid StringOrdinal to signal that no page ordinal was found. 375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension_scoped_prefs_->ReadPrefAsString( 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, kPrefPageOrdinal, &raw_data); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return syncer::StringOrdinal(raw_data); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::SetPageOrdinal( 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& new_page_ordinal) { 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No work is required if the old and new values are the same. 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_page_ordinal.EqualsOrBothInvalid(GetPageOrdinal(extension_id))) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal app_launch_ordinal = GetAppLaunchOrdinal(extension_id); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveOrdinalMapping( 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, GetPageOrdinal(extension_id), app_launch_ordinal); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddOrdinalMapping(extension_id, new_page_ordinal, app_launch_ordinal); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Value* new_value = new_page_ordinal.IsValid() ? 3933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) new base::StringValue(new_page_ordinal.ToInternalValue()) : 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_scoped_prefs_->UpdateExtensionPref( 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPrefPageOrdinal, 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_value); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SyncIfNeeded(extension_id); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::ClearOrdinals(const std::string& extension_id) { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveOrdinalMapping(extension_id, 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPageOrdinal(extension_id), 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAppLaunchOrdinal(extension_id)); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_scoped_prefs_->UpdateExtensionPref( 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, kPrefPageOrdinal, NULL); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_scoped_prefs_->UpdateExtensionPref( 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_id, kPrefAppLaunchOrdinal, NULL); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int ChromeAppSorting::PageStringOrdinalAsInteger( 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& page_ordinal) const { 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!page_ordinal.IsValid()) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PageOrdinalMap::const_iterator it = ntp_ordinal_map_.find(page_ordinal); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return it != ntp_ordinal_map_.end() ? 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::distance(ntp_ordinal_map_.begin(), it) : -1; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::PageIntegerAsStringOrdinal( 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t page_index) { 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_index < ntp_ordinal_map_.size()) { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PageOrdinalMap::const_iterator it = ntp_ordinal_map_.begin(); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::advance(it, page_index); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return it->first; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateOrdinalsIfNecessary(page_index + 1); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ntp_ordinal_map_.rbegin()->first; 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::MarkExtensionAsHidden(const std::string& extension_id) { 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ntp_hidden_extensions_.insert(extension_id); 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 440f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::GetMinOrMaxAppLaunchOrdinalsOnPage( 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& target_page_ordinal, 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppLaunchOrdinalReturn return_type) const { 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(target_page_ordinal.IsValid()); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal return_value; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PageOrdinalMap::const_iterator page = 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ntp_ordinal_map_.find(target_page_ordinal); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page != ntp_ordinal_map_.end()) { 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AppLaunchOrdinalMap& app_list = page->second; 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (app_list.empty()) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return syncer::StringOrdinal(); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (return_type == ChromeAppSorting::MAX_ORDINAL) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = app_list.rbegin()->first; 457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) else if (return_type == ChromeAppSorting::MIN_ORDINAL) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = app_list.begin()->first; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return return_value; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 464f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::InitializePageOrdinalMap( 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::ExtensionIdList& extension_ids) { 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (extensions::ExtensionIdList::const_iterator ext_it = 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_ids.begin(); ext_it != extension_ids.end(); ++ext_it) { 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddOrdinalMapping(*ext_it, 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPageOrdinal(*ext_it), 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAppLaunchOrdinal(*ext_it)); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that the web store app still isn't found in this list, since 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it is added after this loop. 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(*ext_it != extension_misc::kWebStoreAppId); 475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(*ext_it != extension_misc::kChromeAppId); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Include the Web Store App since it is displayed on the NTP. 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal web_store_app_page = 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPageOrdinal(extension_misc::kWebStoreAppId); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (web_store_app_page.IsValid()) { 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddOrdinalMapping(extension_misc::kWebStoreAppId, 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_store_app_page, 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAppLaunchOrdinal(extension_misc::kWebStoreAppId)); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Include the Chrome App since it is displayed in the app launcher. 487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch syncer::StringOrdinal chrome_app_page = 488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch GetPageOrdinal(extension_misc::kChromeAppId); 489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (chrome_app_page.IsValid()) { 490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AddOrdinalMapping(extension_misc::kChromeAppId, 491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch chrome_app_page, 492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch GetAppLaunchOrdinal(extension_misc::kChromeAppId)); 493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::AddOrdinalMapping( 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& page_ordinal, 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& app_launch_ordinal) { 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!page_ordinal.IsValid() || !app_launch_ordinal.IsValid()) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ntp_ordinal_map_[page_ordinal].insert( 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::make_pair(app_launch_ordinal, extension_id)); 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::RemoveOrdinalMapping( 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& page_ordinal, 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& app_launch_ordinal) { 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!page_ordinal.IsValid() || !app_launch_ordinal.IsValid()) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check that the page exists using find to prevent creating a new page 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if |page_ordinal| isn't a used page. 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PageOrdinalMap::iterator page_map = ntp_ordinal_map_.find(page_ordinal); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_map == ntp_ordinal_map_.end()) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (AppLaunchOrdinalMap::iterator it = 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_map->second.find(app_launch_ordinal); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != page_map->second.end(); ++it) { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->second == extension_id) { 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_map->second.erase(it); 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::SyncIfNeeded(const std::string& extension_id) { 5311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (extension_sync_service_) 5321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) extension_sync_service_->SyncOrderingChange(extension_id); 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeAppSorting::CreateDefaultOrdinals() { 53690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (default_ordinals_created_) 53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) default_ordinals_created_ = true; 53990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The following defines the default order of apps. 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> app_ids; 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chromeos::default_app_order::Get(&app_ids); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* kDefaultAppOrder[] = { 546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch extension_misc::kChromeAppId, 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_misc::kWebStoreAppId, 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<const char*> app_ids( 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kDefaultAppOrder, kDefaultAppOrder + arraysize(kDefaultAppOrder)); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal page_ordinal = CreateFirstAppPageOrdinal(); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal app_launch_ordinal = 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateFirstAppLaunchOrdinal(page_ordinal); 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < app_ids.size(); ++i) { 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string extension_id = app_ids[i]; 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_ordinals_[extension_id].page_ordinal = page_ordinal; 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_ordinals_[extension_id].app_launch_ordinal = app_launch_ordinal; 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_launch_ordinal = app_launch_ordinal.CreateAfter(); 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ChromeAppSorting::GetDefaultOrdinals( 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::StringOrdinal* page_ordinal, 56790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) syncer::StringOrdinal* app_launch_ordinal) { 56890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) CreateDefaultOrdinals(); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppOrdinalsMap::const_iterator it = default_ordinals_.find(extension_id); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == default_ordinals_.end()) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_ordinal) 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *page_ordinal = it->second.page_ordinal; 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (app_launch_ordinal) 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *app_launch_ordinal = it->second.app_launch_ordinal; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)syncer::StringOrdinal ChromeAppSorting::ResolveCollision( 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& page_ordinal, 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::StringOrdinal& app_launch_ordinal) const { 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(page_ordinal.IsValid() && app_launch_ordinal.IsValid()); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PageOrdinalMap::const_iterator page_it = ntp_ordinal_map_.find(page_ordinal); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_it == ntp_ordinal_map_.end()) 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return app_launch_ordinal; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AppLaunchOrdinalMap& page = page_it->second; 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppLaunchOrdinalMap::const_iterator app_it = page.find(app_launch_ordinal); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (app_it == page.end()) 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return app_launch_ordinal; 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Finds the next app launcher ordinal. This is done by the following loop 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because this function could be called before FixNTPOrdinalCollisions and 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thus |page| might contains multiple entries with the same app launch 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ordinal. See http://crbug.com/155603 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (app_it != page.end() && app_launch_ordinal.Equals(app_it->first)) 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++app_it; 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is no next after the collision, returns the next ordinal. 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (app_it == page.end()) 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return app_launch_ordinal.CreateAfter(); 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise, returns the ordinal between the collision and the next ordinal. 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return app_launch_ordinal.CreateBetween(app_it->first); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 609f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)size_t ChromeAppSorting::CountItemsVisibleOnNtp( 6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AppLaunchOrdinalMap& m) const { 6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t result = 0; 6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (AppLaunchOrdinalMap::const_iterator it = m.begin(); it != m.end(); 6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it) { 6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& id = it->second; 6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ntp_hidden_extensions_.count(id) == 0) 6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result++; 6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return result; 6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 620f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 621f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace extensions 622