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 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_EXTENSIONS_CHROME_APP_SORTING_H_ 6 #define CHROME_BROWSER_EXTENSIONS_CHROME_APP_SORTING_H_ 7 8 #include <stddef.h> 9 10 #include <map> 11 #include <set> 12 #include <string> 13 #include <vector> 14 15 #include "base/macros.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/scoped_observer.h" 18 #include "chrome/browser/web_applications/components/app_registrar.h" 19 #include "chrome/browser/web_applications/components/app_registrar_observer.h" 20 #include "chrome/browser/web_applications/components/app_registry_controller.h" 21 #include "chrome/browser/web_applications/components/web_app_id.h" 22 #include "components/sync/model/string_ordinal.h" 23 #include "extensions/browser/app_sorting.h" 24 #include "extensions/browser/extension_prefs.h" 25 #include "extensions/common/extension_id.h" 26 27 namespace web_app { 28 class WebApp; 29 class WebAppRegistrar; 30 } // namespace web_app 31 32 namespace extensions { 33 34 class ChromeAppSorting : public AppSorting, 35 public web_app::AppRegistrarObserver { 36 public: 37 explicit ChromeAppSorting(content::BrowserContext* browser_context); 38 ~ChromeAppSorting() override; 39 40 // AppSorting implementation: 41 void InitializePageOrdinalMapFromWebApps() override; 42 void FixNTPOrdinalCollisions() override; 43 void EnsureValidOrdinals( 44 const std::string& extension_id, 45 const syncer::StringOrdinal& suggested_page) override; 46 bool GetDefaultOrdinals(const std::string& extension_id, 47 syncer::StringOrdinal* page_ordinal, 48 syncer::StringOrdinal* app_launch_ordinal) override; 49 void OnExtensionMoved(const std::string& moved_extension_id, 50 const std::string& predecessor_extension_id, 51 const std::string& successor_extension_id) override; 52 syncer::StringOrdinal GetAppLaunchOrdinal( 53 const std::string& extension_id) const override; 54 void SetAppLaunchOrdinal( 55 const std::string& extension_id, 56 const syncer::StringOrdinal& new_app_launch_ordinal) override; 57 syncer::StringOrdinal CreateFirstAppLaunchOrdinal( 58 const syncer::StringOrdinal& page_ordinal) const override; 59 syncer::StringOrdinal CreateNextAppLaunchOrdinal( 60 const syncer::StringOrdinal& page_ordinal) const override; 61 syncer::StringOrdinal CreateFirstAppPageOrdinal() const override; 62 syncer::StringOrdinal GetNaturalAppPageOrdinal() const override; 63 syncer::StringOrdinal GetPageOrdinal( 64 const std::string& extension_id) const override; 65 void SetPageOrdinal(const std::string& extension_id, 66 const syncer::StringOrdinal& new_page_ordinal) override; 67 void ClearOrdinals(const std::string& extension_id) override; 68 int PageStringOrdinalAsInteger( 69 const syncer::StringOrdinal& page_ordinal) const override; 70 syncer::StringOrdinal PageIntegerAsStringOrdinal(size_t page_index) override; 71 void SetExtensionVisible(const std::string& extension_id, 72 bool visible) override; 73 74 // AppRegistrarObserver implementation: 75 void OnWebAppInstalled(const web_app::AppId& app_id) override; 76 void OnWebAppsWillBeUpdatedFromSync( 77 const std::vector<const web_app::WebApp*>& updated_apps_state) override; 78 void OnAppRegistrarDestroyed() override; 79 80 private: 81 // The StringOrdinal is the app launch ordinal and the string is the extension 82 // id. 83 typedef std::multimap< 84 syncer::StringOrdinal, std::string, 85 syncer::StringOrdinal::LessThanFn> AppLaunchOrdinalMap; 86 // The StringOrdinal is the page ordinal and the AppLaunchOrdinalMap is the 87 // contents of that page. 88 typedef std::map< 89 syncer::StringOrdinal, AppLaunchOrdinalMap, 90 syncer::StringOrdinal::LessThanFn> PageOrdinalMap; 91 92 // Unit tests. 93 friend class ChromeAppSortingDefaultOrdinalsBase; 94 friend class ChromeAppSortingGetMinOrMaxAppLaunchOrdinalsOnPage; 95 friend class ChromeAppSortingInitialize; 96 friend class ChromeAppSortingInitializeWithNoApps; 97 friend class ChromeAppSortingPageOrdinalMapping; 98 friend class ChromeAppSortingSetExtensionVisible; 99 100 // An enum used by GetMinOrMaxAppLaunchOrdinalsOnPage to specify which 101 // value should be returned. 102 enum AppLaunchOrdinalReturn {MIN_ORDINAL, MAX_ORDINAL}; 103 104 // Maps an app id to its ordinals. 105 struct AppOrdinals { 106 AppOrdinals(); 107 AppOrdinals(const AppOrdinals& other); 108 ~AppOrdinals(); 109 110 syncer::StringOrdinal page_ordinal; 111 syncer::StringOrdinal app_launch_ordinal; 112 }; 113 typedef std::map<std::string, AppOrdinals> AppOrdinalsMap; 114 115 // This function returns the lowest ordinal on |page_ordinal| if 116 // |return_value| == AppLaunchOrdinalReturn::MIN_ORDINAL, otherwise it returns 117 // the largest ordinal on |page_ordinal|. If there are no apps on the page 118 // then an invalid StringOrdinal is returned. It is an error to call this 119 // function with an invalid |page_ordinal|. 120 syncer::StringOrdinal GetMinOrMaxAppLaunchOrdinalsOnPage( 121 const syncer::StringOrdinal& page_ordinal, 122 AppLaunchOrdinalReturn return_type) const; 123 124 // Initialize the |ntp_ordinal_map_| with the page ordinals used by the 125 // given extensions or by fetching web apps. 126 void InitializePageOrdinalMap( 127 const std::vector<std::string>& extension_or_app_ids); 128 129 // Migrates the app launcher and page index values. 130 void MigrateAppIndex( 131 const extensions::ExtensionIdList& extension_ids); 132 133 // Called to add a new mapping value for |extension_id| with a page ordinal 134 // of |page_ordinal| and a app launch ordinal of |app_launch_ordinal|. This 135 // works with valid and invalid StringOrdinals. 136 void AddOrdinalMapping(const std::string& extension_id, 137 const syncer::StringOrdinal& page_ordinal, 138 const syncer::StringOrdinal& app_launch_ordinal); 139 140 // Ensures |ntp_ordinal_map_| is of |minimum_size| number of entries. 141 void CreateOrdinalsIfNecessary(size_t minimum_size); 142 143 // Removes the mapping for |extension_id| with a page ordinal of 144 // |page_ordinal| and a app launch ordinal of |app_launch_ordinal|. If there 145 // is not matching map, nothing happens. This works with valid and invalid 146 // StringOrdinals. 147 void RemoveOrdinalMapping(const std::string& extension_id, 148 const syncer::StringOrdinal& page_ordinal, 149 const syncer::StringOrdinal& app_launch_ordinal); 150 151 // Syncs the extension if needed. It is an error to call this if the 152 // extension is not an application. 153 void SyncIfNeeded(const std::string& extension_id); 154 155 // Creates the default ordinals. 156 void CreateDefaultOrdinals(); 157 158 // Returns |app_launch_ordinal| if it has no collision in the page specified 159 // by |page_ordinal|. Otherwise, returns an ordinal after |app_launch_ordinal| 160 // that has no conflict. 161 syncer::StringOrdinal ResolveCollision( 162 const syncer::StringOrdinal& page_ordinal, 163 const syncer::StringOrdinal& app_launch_ordinal) const; 164 165 // Returns the number of items in |m| visible on the new tab page. 166 size_t CountItemsVisibleOnNtp(const AppLaunchOrdinalMap& m) const; 167 168 content::BrowserContext* const browser_context_ = nullptr; 169 const web_app::WebAppRegistrar* web_app_registrar_ = nullptr; 170 web_app::WebAppSyncBridge* web_app_sync_bridge_ = nullptr; 171 ScopedObserver<web_app::AppRegistrar, web_app::AppRegistrarObserver> 172 app_registrar_observer_{this}; 173 174 // A map of all the StringOrdinal page ordinals mapping to the collections of 175 // app launch ordinals that exist on that page. This is used for mapping 176 // StringOrdinals to their Integer equivalent as well as quick lookup of the 177 // any collision of on the NTP (icons with the same page and same app launch 178 // ordinals). The possiblity of collisions means that a multimap must be used 179 // (although the collisions must all be resolved once all the syncing is 180 // done). 181 PageOrdinalMap ntp_ordinal_map_; 182 183 // Defines the default ordinals. 184 AppOrdinalsMap default_ordinals_; 185 186 // Used to construct the default ordinals once when needed instead of on 187 // construction when the app order may not have been determined. 188 bool default_ordinals_created_; 189 190 // The set of extensions that don't appear in the new tab page. 191 std::set<std::string> ntp_hidden_extensions_; 192 193 base::WeakPtrFactory<ChromeAppSorting> weak_factory_{this}; 194 195 DISALLOW_COPY_AND_ASSIGN(ChromeAppSorting); 196 }; 197 198 } // namespace extensions 199 200 #endif // CHROME_BROWSER_EXTENSIONS_CHROME_APP_SORTING_H_ 201