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/ui/webui/ntp/app_launcher_handler.h" | 5 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" |
6 | 6 |
| 7 #include <algorithm> |
7 #include <string> | 8 #include <string> |
8 #include <vector> | 9 #include <vector> |
9 | 10 |
| 11 |
| 12 #include "base/json/json_writer.h" |
| 13 |
| 14 |
10 #include "base/auto_reset.h" | 15 #include "base/auto_reset.h" |
11 #include "base/bind.h" | 16 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 17 #include "base/bind_helpers.h" |
13 #include "base/i18n/rtl.h" | 18 #include "base/i18n/rtl.h" |
14 #include "base/metrics/histogram.h" | 19 #include "base/metrics/histogram.h" |
15 #include "base/string_number_conversions.h" | 20 #include "base/string_number_conversions.h" |
16 #include "base/string_split.h" | 21 #include "base/string_split.h" |
17 #include "base/string_util.h" | 22 #include "base/string_util.h" |
18 #include "base/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
19 #include "base/values.h" | 24 #include "base/values.h" |
20 #include "chrome/browser/extensions/app_notification_manager.h" | 25 #include "chrome/browser/extensions/app_notification_manager.h" |
21 #include "chrome/browser/extensions/apps_promo.h" | 26 #include "chrome/browser/extensions/apps_promo.h" |
22 #include "chrome/browser/extensions/crx_installer.h" | 27 #include "chrome/browser/extensions/crx_installer.h" |
23 #include "chrome/browser/extensions/extension_prefs.h" | 28 #include "chrome/browser/extensions/extension_prefs.h" |
24 #include "chrome/browser/extensions/extension_service.h" | 29 #include "chrome/browser/extensions/extension_service.h" |
25 #include "chrome/browser/prefs/pref_service.h" | 30 #include "chrome/browser/prefs/pref_service.h" |
26 #include "chrome/browser/prefs/scoped_user_pref_update.h" | 31 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
27 #include "chrome/browser/profiles/profile.h" | 32 #include "chrome/browser/profiles/profile.h" |
28 #include "chrome/browser/ui/browser.h" | 33 #include "chrome/browser/ui/browser.h" |
29 #include "chrome/browser/ui/browser_list.h" | 34 #include "chrome/browser/ui/browser_list.h" |
30 #include "chrome/browser/ui/browser_window.h" | 35 #include "chrome/browser/ui/browser_window.h" |
31 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" | 36 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" |
32 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" | 37 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" |
33 #include "chrome/browser/ui/webui/web_ui_util.h" | 38 #include "chrome/browser/ui/webui/web_ui_util.h" |
34 #include "chrome/common/chrome_notification_types.h" | 39 #include "chrome/common/chrome_notification_types.h" |
| 40 #include "chrome/common/extensions/extension_constants.h" |
35 #include "chrome/common/extensions/extension.h" | 41 #include "chrome/common/extensions/extension.h" |
36 #include "chrome/common/extensions/extension_constants.h" | |
37 #include "chrome/common/extensions/extension_icon_set.h" | 42 #include "chrome/common/extensions/extension_icon_set.h" |
38 #include "chrome/common/extensions/extension_resource.h" | 43 #include "chrome/common/extensions/extension_resource.h" |
39 #include "chrome/common/favicon_url.h" | 44 #include "chrome/common/favicon_url.h" |
40 #include "chrome/common/pref_names.h" | 45 #include "chrome/common/pref_names.h" |
| 46 #include "chrome/common/string_ordinal.h" |
41 #include "chrome/common/url_constants.h" | 47 #include "chrome/common/url_constants.h" |
42 #include "chrome/common/web_apps.h" | 48 #include "chrome/common/web_apps.h" |
43 #include "content/browser/webui/web_ui.h" | 49 #include "content/browser/webui/web_ui.h" |
44 #include "content/public/browser/notification_service.h" | 50 #include "content/public/browser/notification_service.h" |
45 #include "googleurl/src/gurl.h" | 51 #include "googleurl/src/gurl.h" |
46 #include "grit/browser_resources.h" | 52 #include "grit/browser_resources.h" |
47 #include "grit/generated_resources.h" | 53 #include "grit/generated_resources.h" |
48 #include "net/base/escape.h" | 54 #include "net/base/escape.h" |
49 #include "ui/base/animation/animation.h" | 55 #include "ui/base/animation/animation.h" |
50 #include "ui/base/l10n/l10n_util.h" | 56 #include "ui/base/l10n/l10n_util.h" |
51 #include "ui/gfx/codec/png_codec.h" | 57 #include "ui/gfx/codec/png_codec.h" |
52 | 58 |
53 using content::WebContents; | 59 using content::WebContents; |
54 | 60 |
55 namespace { | 61 namespace { |
56 | 62 |
57 const net::UnescapeRule::Type kUnescapeRules = | 63 const net::UnescapeRule::Type kUnescapeRules = |
58 net::UnescapeRule::NORMAL | net::UnescapeRule::URL_SPECIAL_CHARS; | 64 net::UnescapeRule::NORMAL | net::UnescapeRule::URL_SPECIAL_CHARS; |
59 | 65 |
60 extension_misc::AppLaunchBucket ParseLaunchSource( | 66 extension_misc::AppLaunchBucket ParseLaunchSource( |
61 const std::string& launch_source) { | 67 const std::string& launch_source) { |
62 int bucket_num = extension_misc::APP_LAUNCH_BUCKET_INVALID; | 68 int bucket_num = extension_misc::APP_LAUNCH_BUCKET_INVALID; |
63 base::StringToInt(launch_source, &bucket_num); | 69 base::StringToInt(launch_source, &bucket_num); |
64 extension_misc::AppLaunchBucket bucket = | 70 extension_misc::AppLaunchBucket bucket = |
65 static_cast<extension_misc::AppLaunchBucket>(bucket_num); | 71 static_cast<extension_misc::AppLaunchBucket>(bucket_num); |
66 CHECK(bucket < extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); | 72 CHECK(bucket < extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
67 return bucket; | 73 return bucket; |
68 } | 74 } |
69 | 75 |
| 76 enum PageListPrefMigrationUMABuckets { |
| 77 NONE_REQUIRED = 0, |
| 78 LIST_TO_DICTIONARY = 1, |
| 79 BOUNDARY_BUCKET, |
| 80 }; |
| 81 |
| 82 // Returns whether the original ordinal was valid. |
| 83 static void EnsurePageOrdinalIsValid(const Extension* extension, |
| 84 ExtensionPrefs* ext_prefs) { |
| 85 DCHECK(extension && ext_prefs); |
| 86 StringOrdinal page_ordinal = ext_prefs->GetPageOrdinal(extension->id()); |
| 87 |
| 88 // Make sure every app has a page ordinal (some predate the page ordinal). |
| 89 if (!page_ordinal.IsValid()) { |
| 90 // If the ordinal lacking app is the webstore, put it on the first page. |
| 91 page_ordinal = extension->id() == extension_misc::kWebStoreAppId ? |
| 92 ext_prefs->CreateFirstAppPageOrdinal() : |
| 93 ext_prefs->GetNaturalAppPageOrdinal(); |
| 94 LOG(ERROR) << "extension(" << extension->id() << ") didn't have a valid page
ordinal! Creating one for it as " << page_ordinal.ToString(); |
| 95 ext_prefs->SetPageOrdinal(extension->id(), page_ordinal); |
| 96 } |
| 97 } |
| 98 |
70 } // namespace | 99 } // namespace |
71 | 100 |
72 AppLauncherHandler::AppInstallInfo::AppInstallInfo() {} | 101 AppLauncherHandler::AppInstallInfo::AppInstallInfo() {} |
73 | 102 |
74 AppLauncherHandler::AppInstallInfo::~AppInstallInfo() {} | 103 AppLauncherHandler::AppInstallInfo::~AppInstallInfo() {} |
75 | 104 |
76 AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service) | 105 AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service) |
77 : extension_service_(extension_service), | 106 : extension_service_(extension_service), |
78 ignore_changes_(false), | 107 ignore_changes_(false), |
79 attempted_bookmark_app_install_(false), | 108 attempted_bookmark_app_install_(false), |
80 has_loaded_apps_(false) { | 109 has_loaded_apps_(false), |
| 110 uninstall_from_page_(false) { |
81 } | 111 } |
82 | 112 |
83 AppLauncherHandler::~AppLauncherHandler() {} | 113 AppLauncherHandler::~AppLauncherHandler() {} |
84 | 114 |
85 // Serializes |notification| into a new DictionaryValue which the caller then | 115 // Serializes |notification| into a new DictionaryValue which the caller then |
86 // owns. | 116 // owns. |
87 static DictionaryValue* SerializeNotification( | 117 static DictionaryValue* SerializeNotification( |
88 const AppNotification& notification) { | 118 const AppNotification& notification) { |
89 DictionaryValue* dictionary = new DictionaryValue(); | 119 DictionaryValue* dictionary = new DictionaryValue(); |
90 dictionary->SetString("title", notification.title()); | 120 dictionary->SetString("title", notification.title()); |
(...skipping 12 matching lines...) Expand all Loading... |
103 (extension->id() == extension_misc::kCloudPrintAppId)) { | 133 (extension->id() == extension_misc::kCloudPrintAppId)) { |
104 return true; | 134 return true; |
105 } | 135 } |
106 return false; | 136 return false; |
107 } | 137 } |
108 | 138 |
109 void AppLauncherHandler::CreateAppInfo(const Extension* extension, | 139 void AppLauncherHandler::CreateAppInfo(const Extension* extension, |
110 const AppNotification* notification, | 140 const AppNotification* notification, |
111 ExtensionService* service, | 141 ExtensionService* service, |
112 DictionaryValue* value) { | 142 DictionaryValue* value) { |
| 143 // Change this check if you'd like to pass a non-empty dictionary here. |
| 144 DCHECK(value && value->empty()); |
| 145 |
113 bool enabled = service->IsExtensionEnabled(extension->id()) && | 146 bool enabled = service->IsExtensionEnabled(extension->id()) && |
114 !service->GetTerminatedExtension(extension->id()); | 147 !service->GetTerminatedExtension(extension->id()); |
115 bool icon_big_exists = true; | 148 bool icon_big_exists = true; |
116 // Instead of setting grayscale here, we do it in apps_page.js. | 149 // Instead of setting grayscale here, we do it in apps_page.js. |
117 GURL icon_big = | 150 GURL icon_big = |
118 ExtensionIconSource::GetIconURL(extension, | 151 ExtensionIconSource::GetIconURL(extension, |
119 Extension::EXTENSION_ICON_LARGE, | 152 Extension::EXTENSION_ICON_LARGE, |
120 ExtensionIconSet::MATCH_EXACTLY, | 153 ExtensionIconSet::MATCH_EXACTLY, |
121 false, &icon_big_exists); | 154 false, &icon_big_exists); |
122 bool icon_small_exists = true; | 155 bool icon_small_exists = true; |
(...skipping 26 matching lines...) Expand all Loading... |
149 value->SetInteger("launch_type", | 182 value->SetInteger("launch_type", |
150 prefs->GetLaunchType(extension->id(), | 183 prefs->GetLaunchType(extension->id(), |
151 ExtensionPrefs::LAUNCH_DEFAULT)); | 184 ExtensionPrefs::LAUNCH_DEFAULT)); |
152 value->SetBoolean("offline_enabled", extension->offline_enabled()); | 185 value->SetBoolean("offline_enabled", extension->offline_enabled()); |
153 value->SetBoolean("is_component", | 186 value->SetBoolean("is_component", |
154 extension->location() == Extension::COMPONENT); | 187 extension->location() == Extension::COMPONENT); |
155 value->SetBoolean("is_webstore", | 188 value->SetBoolean("is_webstore", |
156 extension->id() == extension_misc::kWebStoreAppId); | 189 extension->id() == extension_misc::kWebStoreAppId); |
157 | 190 |
158 if (extension->HasAPIPermission(ExtensionAPIPermission::kAppNotifications)) { | 191 if (extension->HasAPIPermission(ExtensionAPIPermission::kAppNotifications)) { |
159 ExtensionPrefs* prefs = service->extension_prefs(); | |
160 value->SetBoolean("notifications_disabled", | 192 value->SetBoolean("notifications_disabled", |
161 prefs->IsAppNotificationDisabled(extension->id())); | 193 prefs->IsAppNotificationDisabled(extension->id())); |
162 } | 194 } |
163 | 195 |
164 if (notification) | 196 if (notification) |
165 value->Set("notification", SerializeNotification(*notification)); | 197 value->Set("notification", SerializeNotification(*notification)); |
166 | 198 |
| 199 EnsurePageOrdinalIsValid(extension, prefs); |
167 StringOrdinal page_ordinal = prefs->GetPageOrdinal(extension->id()); | 200 StringOrdinal page_ordinal = prefs->GetPageOrdinal(extension->id()); |
168 if (!page_ordinal.IsValid()) { | 201 value->SetString("page_ordinal", page_ordinal.ToString()); |
169 // Make sure every app has a page ordinal (some predate the page ordinal). | |
170 // The webstore app should be on the first page. | |
171 page_ordinal = extension->id() == extension_misc::kWebStoreAppId ? | |
172 prefs->CreateFirstAppPageOrdinal() : prefs->GetNaturalAppPageOrdinal(); | |
173 prefs->SetPageOrdinal(extension->id(), page_ordinal); | |
174 } | |
175 // We convert the page_ordinal to an integer because the pages are referenced | |
176 // from within an array in the javascript code, which can't be easily | |
177 // changed to handle the StringOrdinal values, so we do the conversion here. | |
178 int page_index = prefs->PageStringOrdinalAsInteger(page_ordinal); | |
179 value->SetInteger("page_index", page_index >= 0 ? page_index : 0); | |
180 | 202 |
181 StringOrdinal app_launch_ordinal = | 203 StringOrdinal app_launch_ordinal = |
182 prefs->GetAppLaunchOrdinal(extension->id()); | 204 prefs->GetAppLaunchOrdinal(extension->id()); |
183 if (!app_launch_ordinal.IsValid()) { | 205 if (!app_launch_ordinal.IsValid()) { |
184 // Make sure every app has a launch ordinal (some predate the launch | 206 // Make sure every app has a launch ordinal (some predate the launch |
185 // ordinal). The webstore's app launch ordinal is always set to the first | 207 // ordinal). The webstore's app launch ordinal is always set to the first |
186 // position. | 208 // position. |
187 app_launch_ordinal = extension->id() == extension_misc::kWebStoreAppId ? | 209 app_launch_ordinal = extension->id() == extension_misc::kWebStoreAppId ? |
188 prefs->CreateFirstAppLaunchOrdinal(page_ordinal) : | 210 prefs->CreateFirstAppLaunchOrdinal(page_ordinal) : |
189 prefs->CreateNextAppLaunchOrdinal(page_ordinal); | 211 prefs->CreateNextAppLaunchOrdinal(page_ordinal); |
190 prefs->SetAppLaunchOrdinal(extension->id(), app_launch_ordinal); | 212 prefs->SetAppLaunchOrdinal(extension->id(), app_launch_ordinal); |
191 } | 213 } |
192 value->SetString("app_launch_ordinal", app_launch_ordinal.ToString()); | 214 value->SetString("app_launch_ordinal", app_launch_ordinal.ToString()); |
193 } | 215 } |
194 | 216 |
195 void AppLauncherHandler::RegisterMessages() { | 217 void AppLauncherHandler::RegisterMessages() { |
196 registrar_.Add(this, chrome::NOTIFICATION_APP_INSTALLED_TO_NTP, | 218 registrar_.Add(this, chrome::NOTIFICATION_APP_INSTALLED_TO_NTP, |
197 content::Source<WebContents>(web_ui()->web_contents())); | 219 content::Source<WebContents>(web_ui()->web_contents())); |
198 | 220 |
| 221 web_ui()->RegisterMessageCallback("deleteEmptyAppsPage", |
| 222 base::Bind(&AppLauncherHandler::HandleDeleteEmptyAppsPage, |
| 223 base::Unretained(this))); |
199 web_ui()->RegisterMessageCallback("getApps", | 224 web_ui()->RegisterMessageCallback("getApps", |
200 base::Bind(&AppLauncherHandler::HandleGetApps, | 225 base::Bind(&AppLauncherHandler::HandleGetApps, |
201 base::Unretained(this))); | 226 base::Unretained(this))); |
202 web_ui()->RegisterMessageCallback("launchApp", | 227 web_ui()->RegisterMessageCallback("launchApp", |
203 base::Bind(&AppLauncherHandler::HandleLaunchApp, | 228 base::Bind(&AppLauncherHandler::HandleLaunchApp, |
204 base::Unretained(this))); | 229 base::Unretained(this))); |
205 web_ui()->RegisterMessageCallback("setLaunchType", | 230 web_ui()->RegisterMessageCallback("setLaunchType", |
206 base::Bind(&AppLauncherHandler::HandleSetLaunchType, | 231 base::Bind(&AppLauncherHandler::HandleSetLaunchType, |
207 base::Unretained(this))); | 232 base::Unretained(this))); |
208 web_ui()->RegisterMessageCallback("uninstallApp", | 233 web_ui()->RegisterMessageCallback("uninstallApp", |
209 base::Bind(&AppLauncherHandler::HandleUninstallApp, | 234 base::Bind(&AppLauncherHandler::HandleUninstallApp, |
210 base::Unretained(this))); | 235 base::Unretained(this))); |
211 web_ui()->RegisterMessageCallback("hideAppsPromo", | 236 web_ui()->RegisterMessageCallback("hideAppsPromo", |
212 base::Bind(&AppLauncherHandler::HandleHideAppsPromo, | 237 base::Bind(&AppLauncherHandler::HandleHideAppsPromo, |
213 base::Unretained(this))); | 238 base::Unretained(this))); |
214 web_ui()->RegisterMessageCallback("createAppShortcut", | 239 web_ui()->RegisterMessageCallback("createAppShortcut", |
215 base::Bind(&AppLauncherHandler::HandleCreateAppShortcut, | 240 base::Bind(&AppLauncherHandler::HandleCreateAppShortcut, |
216 base::Unretained(this))); | 241 base::Unretained(this))); |
217 web_ui()->RegisterMessageCallback("reorderApps", | 242 web_ui()->RegisterMessageCallback("reorderApps", |
218 base::Bind(&AppLauncherHandler::HandleReorderApps, | 243 base::Bind(&AppLauncherHandler::HandleReorderApps, |
219 base::Unretained(this))); | 244 base::Unretained(this))); |
220 web_ui()->RegisterMessageCallback("setPageIndex", | 245 web_ui()->RegisterMessageCallback("setPageIndex", |
221 base::Bind(&AppLauncherHandler::HandleSetPageIndex, | 246 base::Bind(&AppLauncherHandler::HandleSetPageIndex, |
222 base::Unretained(this))); | 247 base::Unretained(this))); |
223 web_ui()->RegisterMessageCallback("promoSeen", | 248 web_ui()->RegisterMessageCallback("promoSeen", |
224 base::Bind(&AppLauncherHandler::HandlePromoSeen, | 249 base::Bind(&AppLauncherHandler::HandlePromoSeen, |
225 base::Unretained(this))); | 250 base::Unretained(this))); |
226 web_ui()->RegisterMessageCallback("saveAppPageName", | 251 web_ui()->RegisterMessageCallback("saveAppsPageName", |
227 base::Bind(&AppLauncherHandler::HandleSaveAppPageName, | 252 base::Bind(&AppLauncherHandler::HandleSaveAppsPageName, |
228 base::Unretained(this))); | 253 base::Unretained(this))); |
229 web_ui()->RegisterMessageCallback("generateAppForLink", | 254 web_ui()->RegisterMessageCallback("generateAppForLink", |
230 base::Bind(&AppLauncherHandler::HandleGenerateAppForLink, | 255 base::Bind(&AppLauncherHandler::HandleGenerateAppForLink, |
231 base::Unretained(this))); | 256 base::Unretained(this))); |
232 web_ui()->RegisterMessageCallback("recordAppLaunchByURL", | 257 web_ui()->RegisterMessageCallback("recordAppLaunchByURL", |
233 base::Bind(&AppLauncherHandler::HandleRecordAppLaunchByURL, | 258 base::Bind(&AppLauncherHandler::HandleRecordAppLaunchByURL, |
234 base::Unretained(this))); | 259 base::Unretained(this))); |
235 web_ui()->RegisterMessageCallback("closeNotification", | 260 web_ui()->RegisterMessageCallback("closeNotification", |
236 base::Bind(&AppLauncherHandler::HandleNotificationClose, | 261 base::Bind(&AppLauncherHandler::HandleNotificationClose, |
237 base::Unretained(this))); | 262 base::Unretained(this))); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 content::Details<UnloadedExtensionInfo>(details)->extension; | 320 content::Details<UnloadedExtensionInfo>(details)->extension; |
296 if (!extension->is_app()) | 321 if (!extension->is_app()) |
297 return; | 322 return; |
298 | 323 |
299 scoped_ptr<DictionaryValue> app_info(GetAppInfo(extension)); | 324 scoped_ptr<DictionaryValue> app_info(GetAppInfo(extension)); |
300 scoped_ptr<base::FundamentalValue> uninstall_value( | 325 scoped_ptr<base::FundamentalValue> uninstall_value( |
301 Value::CreateBooleanValue( | 326 Value::CreateBooleanValue( |
302 content::Details<UnloadedExtensionInfo>(details)->reason == | 327 content::Details<UnloadedExtensionInfo>(details)->reason == |
303 extension_misc::UNLOAD_REASON_UNINSTALL)); | 328 extension_misc::UNLOAD_REASON_UNINSTALL)); |
304 if (app_info.get()) { | 329 if (app_info.get()) { |
| 330 scoped_ptr<base::FundamentalValue> from_page( |
| 331 Value::CreateBooleanValue(uninstall_from_page_)); |
305 web_ui()->CallJavascriptFunction( | 332 web_ui()->CallJavascriptFunction( |
306 "ntp4.appRemoved", *app_info, *uninstall_value); | 333 "ntp4.appRemoved", *app_info, *uninstall_value, *from_page); |
307 } | 334 } |
308 break; | 335 break; |
309 } | 336 } |
310 case chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED: | 337 case chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED: { |
311 // The promo may not load until a couple seconds after the first NTP view, | 338 DictionaryValue pages; |
312 // so we listen for the load notification and notify the NTP when ready. | 339 const ExtensionSet* extensions = extension_service_->extensions(); |
313 case chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED: | 340 ExtensionPrefs* prefs = extension_service_->extension_prefs(); |
314 // TODO(estade): try to get rid of this inefficient operation. | 341 for (ExtensionSet::const_iterator it = extensions->begin(); |
| 342 it != extensions->end(); ++it) { |
| 343 if (!IsAppExcludedFromList(*it)) { |
| 344 std::string page_ordinal_string = |
| 345 prefs->GetPageOrdinal((*it)->id()).ToString(); |
| 346 if (!pages.HasKey(page_ordinal_string)) |
| 347 pages.Set(page_ordinal_string, new DictionaryValue()); |
| 348 DictionaryValue* page; |
| 349 CHECK(pages.GetDictionary(page_ordinal_string, &page)); |
| 350 page->SetString(prefs->GetAppLaunchOrdinal((*it)->id()).ToString(), |
| 351 (*it)->id()); |
| 352 } |
| 353 } |
| 354 web_ui()->CallJavascriptFunction("ntp4.appsReordered", pages); |
| 355 break; |
| 356 } |
| 357 case chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED: { |
| 358 // The promo may not load until a couple seconds after the first NTP view, |
| 359 // so we listen for the load notification and notify the NTP when ready. |
315 HandleGetApps(NULL); | 360 HandleGetApps(NULL); |
316 break; | 361 break; |
| 362 } |
317 case chrome::NOTIFICATION_PREF_CHANGED: { | 363 case chrome::NOTIFICATION_PREF_CHANGED: { |
| 364 LOG(ERROR) << "Pref changed!"; |
318 DictionaryValue dictionary; | 365 DictionaryValue dictionary; |
319 FillAppDictionary(&dictionary); | 366 FillAppDictionary(&dictionary); |
320 web_ui()->CallJavascriptFunction("appsPrefChangeCallback", dictionary); | 367 web_ui()->CallJavascriptFunction("appsPrefChangeCallback", dictionary); |
321 break; | 368 break; |
322 } | 369 } |
323 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: { | 370 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: { |
324 CrxInstaller* crx_installer = content::Source<CrxInstaller>(source).ptr(); | 371 CrxInstaller* crx_installer = content::Source<CrxInstaller>(source).ptr(); |
325 if (!Profile::FromWebUI(web_ui())->IsSameProfile( | 372 if (!Profile::FromWebUI(web_ui())->IsSameProfile( |
326 crx_installer->profile())) { | 373 crx_installer->profile())) { |
327 return; | 374 return; |
328 } | 375 } |
329 // Fall Through. | 376 // Fall Through. |
330 } | 377 } |
331 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR: { | 378 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR: { |
332 attempted_bookmark_app_install_ = false; | 379 attempted_bookmark_app_install_ = false; |
333 break; | 380 break; |
334 } | 381 } |
335 default: | 382 default: |
336 NOTREACHED(); | 383 NOTREACHED(); |
337 } | 384 } |
338 } | 385 } |
339 | 386 |
| 387 void AppLauncherHandler::RemoveNonAppExtensionOrdinals( |
| 388 const ExtensionSet* extensions) { |
| 389 ExtensionSet::const_iterator it; |
| 390 for (it = extensions->begin(); it != extensions->end(); ++it) { |
| 391 const Extension* extension = *it; |
| 392 // Ensure any previous non-app extensions aren't showing / don't have a page |
| 393 // ordinal or migrated page index. This is necessary because in some |
| 394 // previous versions of chrome, we set a page index for non-app extensions. |
| 395 // Old profiles can persist this error, and this fixes it. This caused |
| 396 // GetNaturalAppPageIndex() to break (see http://crbug.com/98325) before it |
| 397 // was an ordinal value. |
| 398 if (IsAppExcludedFromList(extension)) { |
| 399 ExtensionPrefs* ext_prefs = extension_service_->extension_prefs(); |
| 400 if (ext_prefs->GetPageOrdinal(extension->id()).IsValid()) |
| 401 ext_prefs->ClearPageOrdinal(extension->id()); |
| 402 } |
| 403 } |
| 404 } |
| 405 |
340 void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) { | 406 void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) { |
341 // CreateAppInfo and ClearPageOrdinal can change the extension prefs. | 407 // CreateAppInfo and ClearPageOrdinal can change the extension prefs. |
342 AutoReset<bool> auto_reset(&ignore_changes_, true); | 408 AutoReset<bool> auto_reset(&ignore_changes_, true); |
343 | 409 |
344 ListValue* list = new ListValue(); | 410 RemoveNonAppExtensionOrdinals(extension_service_->extensions()); |
345 const ExtensionSet* extensions = extension_service_->extensions(); | 411 |
346 ExtensionSet::const_iterator it; | 412 // Start NULL, CHECK() that it's not NULL after being populated with names. |
347 for (it = extensions->begin(); it != extensions->end(); ++it) { | 413 DictionaryValue* apps_page_names = NULL; |
348 const Extension* extension = *it; | 414 |
349 if (!IsAppExcludedFromList(extension)) { | 415 // Get all the existing apps' page_ordinals, de-duped and sorted, and make |
350 DictionaryValue* app_info = GetAppInfo(extension); | 416 // sure we've got page names for all the existing pages (or populate with |
351 list->Append(app_info); | 417 // default). If there's a page without any apps on it, delete that pref. |
352 } else { | 418 scoped_ptr<std::vector<std::string> > page_ordinals(PageOrdinalsFromApps()); |
353 // This is necessary because in some previous versions of chrome, we set a | 419 |
354 // page index for non-app extensions. Old profiles can persist this error, | 420 // Most of the time we probably won't need to update, so let's only do this |
355 // and this fixes it. This caused GetNaturalAppPageIndex() to break | 421 // when something changes (during migration or an edge case like mentioned |
356 // (see http://crbug.com/98325) before it was an ordinal value. | 422 // above when the page names pref doesn't match the apps' info). |
357 ExtensionPrefs* prefs = extension_service_->extension_prefs(); | 423 bool update_required = false; |
358 if (prefs->GetPageOrdinal(extension->id()).IsValid()) | 424 |
359 prefs->ClearPageOrdinal(extension->id()); | 425 // If the legacy preference exists, migrate it from a list to a dictionary. |
| 426 // TODO(dbeam): Remove migration when UMA hits sufficiently small number. |
| 427 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); |
| 428 if (prefs->HasPrefPath(prefs::kNTPAppsPageNamesOld)) { |
| 429 LOG(ERROR) << "Migrating from list to dict for page names required!"; |
| 430 apps_page_names = new DictionaryValue(); |
| 431 scoped_ptr<ListValue> apps_page_names_list( |
| 432 prefs->GetList(prefs::kNTPAppsPageNamesOld)->DeepCopy()); |
| 433 string16 default_page_name( |
| 434 l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME)); |
| 435 for (size_t i = 0; i < page_ordinals->size(); ++i) { |
| 436 if (i >= apps_page_names_list->GetSize()) { |
| 437 apps_page_names->Set(page_ordinals->at(i), |
| 438 Value::CreateStringValue(default_page_name)); |
| 439 } else { |
| 440 Value* name; |
| 441 CHECK(apps_page_names_list->Get(i, &name)); |
| 442 apps_page_names->Set(page_ordinals->at(i), name->DeepCopy()); |
| 443 } |
| 444 } |
| 445 // If there were extra entries just ignore, we're deleting whole preference. |
| 446 prefs->ClearPref(prefs::kNTPAppsPageNamesOld); |
| 447 update_required = true; |
| 448 UMA_HISTOGRAM_ENUMERATION("NewTabPage.PageNamesPrefMigration", |
| 449 LIST_TO_DICTIONARY, BOUNDARY_BUCKET); |
| 450 } else { |
| 451 LOG(ERROR) << "No migration required!"; |
| 452 apps_page_names = |
| 453 prefs->GetDictionary(prefs::kNTPAppsPageNames)->DeepCopy(); |
| 454 update_required = SyncPageNamesToApps(apps_page_names); |
| 455 // Log this to more easily track how many folks are done migrating prefs. |
| 456 UMA_HISTOGRAM_ENUMERATION("NewTabPage.PageNamesPrefMigration", |
| 457 NONE_REQUIRED, BOUNDARY_BUCKET); |
| 458 } |
| 459 // There should always be something in this pref (as there should always be at |
| 460 // least one app which requires a page to live on). |
| 461 CHECK(apps_page_names && !apps_page_names->empty()); |
| 462 |
| 463 if (update_required) { |
| 464 LOG(ERROR) << "Something about page names changed, updating!"; |
| 465 scoped_ptr<DictionaryValue> page_names_copy(apps_page_names->DeepCopy()); |
| 466 DictionaryPrefUpdate update(prefs, prefs::kNTPAppsPageNames); |
| 467 update.Get()->Swap(page_names_copy.get()); |
| 468 } |
| 469 |
| 470 std::string json; |
| 471 base::JSONWriter::Write(apps_page_names, false, &json); |
| 472 LOG(ERROR) << apps_page_names->size() << ", " << json; |
| 473 |
| 474 // Create a dictionary structured by pages and app ordinals, like this: |
| 475 // { |
| 476 // "<page_ordinal>": { |
| 477 // "name": <page_name>, |
| 478 // "apps": { |
| 479 // <app_launch_ordinal>": { <app_info> }, |
| 480 // ... |
| 481 // } |
| 482 // ... |
| 483 // }, |
| 484 // ... |
| 485 // } |
| 486 DictionaryValue* apps_pages = new DictionaryValue(); |
| 487 |
| 488 scoped_ptr<const ExtensionSet> installed_extensions( |
| 489 extension_service_->GetAllInstalledExtensions()); |
| 490 |
| 491 for (ExtensionSet::const_iterator it = installed_extensions->begin(); |
| 492 it != installed_extensions->end(); ++it) { |
| 493 if (!IsAppExcludedFromList(*it)) { |
| 494 DictionaryValue* app_info = new DictionaryValue(); |
| 495 CreateAppInfo(*it, NULL, extension_service_, app_info); |
| 496 |
| 497 std::string page_ordinal; |
| 498 DCHECK(app_info->GetString("page_ordinal", &page_ordinal)); |
| 499 LOG(ERROR) << "App had page_ordinal: " << page_ordinal; |
| 500 |
| 501 if (!apps_pages->HasKey(page_ordinal)) |
| 502 apps_pages->Set(page_ordinal, new DictionaryValue()); |
| 503 |
| 504 DictionaryValue* page; |
| 505 DCHECK(apps_pages->GetDictionary(page_ordinal, &page)); |
| 506 |
| 507 if (!page->HasKey("apps")) |
| 508 page->Set("apps", new DictionaryValue()); |
| 509 |
| 510 if (!page->HasKey("name")) { |
| 511 std::string page_name; |
| 512 DCHECK(apps_page_names->GetString(page_ordinal, &page_name)); |
| 513 page->Set("name", Value::CreateStringValue(page_name)); |
| 514 } |
| 515 |
| 516 DictionaryValue* apps; |
| 517 DCHECK(page->GetDictionary("apps", &apps)); |
| 518 |
| 519 std::string app_launch_ordinal; |
| 520 DCHECK(app_info->GetString("app_launch_ordinal", &app_launch_ordinal)); |
| 521 |
| 522 DCHECK(!apps->HasKey(app_launch_ordinal)); |
| 523 apps->Set(app_launch_ordinal, app_info); |
360 } | 524 } |
361 } | 525 } |
| 526 CHECK(apps_pages->size() >= 1); |
| 527 dictionary->Set("appsPages", apps_pages); |
| 528 } |
362 | 529 |
363 extensions = extension_service_->disabled_extensions(); | 530 bool AppLauncherHandler::SyncPageNamesToApps(DictionaryValue* page_names) { |
364 for (it = extensions->begin(); it != extensions->end(); ++it) { | 531 string16 default_page_name = |
365 if (!IsAppExcludedFromList(*it)) { | 532 l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME); |
366 DictionaryValue* app_info = new DictionaryValue(); | 533 bool value_changed = false; |
367 CreateAppInfo(*it, | 534 // Get all the unique page ordinals that the current set of apps has and if no |
368 NULL, | 535 // page name exists for that page yet, create one with the default value. |
369 extension_service_, | 536 scoped_ptr<std::vector<std::string> > ordinals(PageOrdinalsFromApps()); |
370 app_info); | 537 for (std::vector<std::string>::const_iterator it = ordinals->begin(); |
371 list->Append(app_info); | 538 it != ordinals->end(); ++it) { |
| 539 if (!page_names->HasKey(*it)) { |
| 540 LOG(ERROR) << "Found new page ordinal, " << *it << ", setting it to defaul
t page name! (" << default_page_name << ")"; |
| 541 page_names->SetString(*it, default_page_name); |
| 542 value_changed = true; |
372 } | 543 } |
373 } | 544 } |
374 | 545 // Make a copy to avoid invalidating our iterator if a key is deleted. |
375 extensions = extension_service_->terminated_extensions(); | 546 scoped_ptr<DictionaryValue> page_names_copy(page_names->DeepCopy()); |
376 for (it = extensions->begin(); it != extensions->end(); ++it) { | 547 // Look for extraneous pages that no longer have apps on them. |
377 if (!IsAppExcludedFromList(*it)) { | 548 for (DictionaryValue::key_iterator it = page_names->begin_keys(); |
378 DictionaryValue* app_info = new DictionaryValue(); | 549 it != page_names->end_keys(); ++it) { |
379 CreateAppInfo(*it, | 550 if (std::find(ordinals->begin(), ordinals->end(), *it) == ordinals->end()) { |
380 NULL, | 551 LOG(ERROR) << "Found left over page ordinal, " << *it << ", deleting!"; |
381 extension_service_, | 552 DCHECK(page_names_copy->Remove(*it, NULL)); |
382 app_info); | 553 value_changed = true; |
383 list->Append(app_info); | |
384 } | 554 } |
385 } | 555 } |
386 | 556 // Swap with the possibly affected dictionary. |
387 dictionary->Set("apps", list); | 557 page_names->Swap(page_names_copy.get()); |
388 | 558 // Tell the caller whether anything changed in this method. |
389 // TODO(estade): remove these settings when the old NTP is removed. The new | 559 return value_changed; |
390 // NTP does it in js. | |
391 #if defined(OS_MACOSX) | |
392 // App windows are not yet implemented on mac. | |
393 dictionary->SetBoolean("disableAppWindowLaunch", true); | |
394 dictionary->SetBoolean("disableCreateAppShortcut", true); | |
395 #endif | |
396 | |
397 #if defined(OS_CHROMEOS) | |
398 // Making shortcut does not make sense on ChromeOS because it does not have | |
399 // a desktop. | |
400 dictionary->SetBoolean("disableCreateAppShortcut", true); | |
401 #endif | |
402 | |
403 dictionary->SetBoolean( | |
404 "showLauncher", | |
405 extension_service_->apps_promo()->ShouldShowAppLauncher( | |
406 extension_service_->GetAppIds())); | |
407 | |
408 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); | |
409 const ListValue* app_page_names = prefs->GetList(prefs::kNTPAppPageNames); | |
410 if (!app_page_names || !app_page_names->GetSize()) { | |
411 ListPrefUpdate update(prefs, prefs::kNTPAppPageNames); | |
412 ListValue* list = update.Get(); | |
413 list->Set(0, Value::CreateStringValue( | |
414 l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME))); | |
415 dictionary->Set("appPageNames", | |
416 static_cast<ListValue*>(list->DeepCopy())); | |
417 } else { | |
418 dictionary->Set("appPageNames", | |
419 static_cast<ListValue*>(app_page_names->DeepCopy())); | |
420 } | |
421 } | 560 } |
422 | 561 |
423 DictionaryValue* AppLauncherHandler::GetAppInfo(const Extension* extension) { | 562 DictionaryValue* AppLauncherHandler::GetAppInfo(const Extension* extension) { |
424 AppNotificationManager* notification_manager = | 563 AppNotificationManager* notification_manager = |
425 extension_service_->app_notification_manager(); | 564 extension_service_->app_notification_manager(); |
426 DictionaryValue* app_info = new DictionaryValue(); | 565 DictionaryValue* app_info = new DictionaryValue(); |
427 // CreateAppInfo can change the extension prefs. | 566 // CreateAppInfo can change the extension prefs. |
428 AutoReset<bool> auto_reset(&ignore_changes_, true); | 567 AutoReset<bool> auto_reset(&ignore_changes_, true); |
429 CreateAppInfo(extension, | 568 CreateAppInfo(extension, |
430 notification_manager->GetLast(extension->id()), | 569 notification_manager->GetLast(extension->id()), |
431 extension_service_, | 570 extension_service_, |
432 app_info); | 571 app_info); |
433 return app_info; | 572 return app_info; |
434 } | 573 } |
435 | 574 |
| 575 std::vector<std::string>* AppLauncherHandler::PageOrdinalsFromApps() { |
| 576 std::vector<std::string>* pages = new std::vector<std::string>(); |
| 577 const ExtensionSet* extensions = extension_service_->extensions(); |
| 578 ExtensionPrefs* ext_prefs = extension_service_->extension_prefs(); |
| 579 for (ExtensionSet::const_iterator it = extensions->begin(); |
| 580 it != extensions->end(); ++it) { |
| 581 if (!IsAppExcludedFromList(*it)) { |
| 582 EnsurePageOrdinalIsValid(*it, ext_prefs); |
| 583 std::string ordinal(ext_prefs->GetPageOrdinal((*it)->id()).ToString()); |
| 584 if (std::find(pages->begin(), pages->end(), ordinal) == pages->end()) |
| 585 pages->push_back(ordinal); |
| 586 } |
| 587 } |
| 588 std::sort(pages->begin(), pages->end()); |
| 589 return pages; |
| 590 } |
| 591 |
436 void AppLauncherHandler::FillPromoDictionary(DictionaryValue* dictionary) { | 592 void AppLauncherHandler::FillPromoDictionary(DictionaryValue* dictionary) { |
437 AppsPromo::PromoData data = AppsPromo::GetPromo(); | 593 AppsPromo::PromoData data = AppsPromo::GetPromo(); |
438 dictionary->SetString("promoHeader", data.header); | 594 dictionary->SetString("promoHeader", data.header); |
439 dictionary->SetString("promoButton", data.button); | 595 dictionary->SetString("promoButton", data.button); |
440 dictionary->SetString("promoLink", data.link.spec()); | 596 dictionary->SetString("promoLink", data.link.spec()); |
441 dictionary->SetString("promoLogo", data.logo.spec()); | 597 dictionary->SetString("promoLogo", data.logo.spec()); |
442 dictionary->SetString("promoExpire", data.expire); | 598 dictionary->SetString("promoExpire", data.expire); |
443 } | 599 } |
444 | 600 |
| 601 void AppLauncherHandler::HandleDeleteEmptyAppsPage(const ListValue* args) { |
| 602 std::string page_ordinal; |
| 603 CHECK(args->GetString(0, &page_ordinal)); |
| 604 |
| 605 AutoReset<bool> auto_reset(&ignore_changes_, true); |
| 606 |
| 607 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); |
| 608 const DictionaryValue* dict = prefs->GetDictionary(prefs::kNTPAppsPageNames); |
| 609 std::string value; |
| 610 DCHECK(dict->GetString(page_ordinal, &value)); |
| 611 |
| 612 LOG(ERROR) << "Its value is: " << value; |
| 613 |
| 614 // Ensure the page we're deleting is empty. |
| 615 scoped_ptr<std::vector<std::string> > pages(PageOrdinalsFromApps()); |
| 616 DCHECK(std::find(pages->begin(), pages->end(), page_ordinal) == pages->end()); |
| 617 |
| 618 DictionaryPrefUpdate update(prefs, prefs::kNTPAppsPageNames); |
| 619 DCHECK(update.Get()->Remove(page_ordinal, NULL)); |
| 620 |
| 621 dict = prefs->GetDictionary(prefs::kNTPAppsPageNames); |
| 622 |
| 623 std::string json; |
| 624 base::JSONWriter::Write(dict, false, &json); |
| 625 LOG(ERROR) << "now is: " << dict->size() << ", " << json; |
| 626 } |
| 627 |
| 628 void AppLauncherHandler::CleanupAfterUninstall() { |
| 629 uninstall_from_page_ = false; |
| 630 extension_id_prompting_ = ""; |
| 631 } |
| 632 |
445 void AppLauncherHandler::HandleGetApps(const ListValue* args) { | 633 void AppLauncherHandler::HandleGetApps(const ListValue* args) { |
446 DictionaryValue dictionary; | 634 DictionaryValue dictionary; |
447 | 635 |
448 // Tell the client whether to show the promo for this view. We don't do this | 636 // Tell the client whether to show the promo for this view. We don't do this |
449 // in the case of PREF_CHANGED because: | 637 // in the case of PREF_CHANGED because: |
450 // | 638 // |
451 // a) At that point in time, depending on the pref that changed, it can look | 639 // a) At that point in time, depending on the pref that changed, it can look |
452 // like the set of apps installed has changed, and we will mark the promo | 640 // like the set of apps installed has changed, and we will mark the promo |
453 // expired. | 641 // expired. |
454 // b) Conceptually, it doesn't really make sense to count a | 642 // b) Conceptually, it doesn't really make sense to count a |
(...skipping 20 matching lines...) Expand all Loading... |
475 SetAppToBeHighlighted(); | 663 SetAppToBeHighlighted(); |
476 FillAppDictionary(&dictionary); | 664 FillAppDictionary(&dictionary); |
477 web_ui()->CallJavascriptFunction("getAppsCallback", dictionary); | 665 web_ui()->CallJavascriptFunction("getAppsCallback", dictionary); |
478 | 666 |
479 // First time we get here we set up the observer so that we can tell update | 667 // First time we get here we set up the observer so that we can tell update |
480 // the apps as they change. | 668 // the apps as they change. |
481 if (!has_loaded_apps_) { | 669 if (!has_loaded_apps_) { |
482 pref_change_registrar_.Init( | 670 pref_change_registrar_.Init( |
483 extension_service_->extension_prefs()->pref_service()); | 671 extension_service_->extension_prefs()->pref_service()); |
484 pref_change_registrar_.Add(ExtensionPrefs::kExtensionsPref, this); | 672 pref_change_registrar_.Add(ExtensionPrefs::kExtensionsPref, this); |
485 pref_change_registrar_.Add(prefs::kNTPAppPageNames, this); | 673 pref_change_registrar_.Add(prefs::kNTPAppsPageNames, this); |
486 | 674 |
487 registrar_.Add(this, chrome::NOTIFICATION_APP_NOTIFICATION_STATE_CHANGED, | 675 registrar_.Add(this, chrome::NOTIFICATION_APP_NOTIFICATION_STATE_CHANGED, |
488 content::Source<Profile>(profile)); | 676 content::Source<Profile>(profile)); |
489 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | 677 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
490 content::Source<Profile>(profile)); | 678 content::Source<Profile>(profile)); |
491 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 679 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
492 content::Source<Profile>(profile)); | 680 content::Source<Profile>(profile)); |
493 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED, | 681 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED, |
494 content::Source<ExtensionPrefs>(extension_service_->extension_prefs())); | 682 content::Source<ExtensionPrefs>(extension_service_->extension_prefs())); |
495 registrar_.Add(this, chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED, | 683 registrar_.Add(this, chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED, |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
608 if (!extension_id_prompting_.empty()) | 796 if (!extension_id_prompting_.empty()) |
609 return; // Only one prompt at a time. | 797 return; // Only one prompt at a time. |
610 | 798 |
611 extension_id_prompting_ = extension_id; | 799 extension_id_prompting_ = extension_id; |
612 | 800 |
613 bool dont_confirm = false; | 801 bool dont_confirm = false; |
614 if (args->GetBoolean(1, &dont_confirm) && dont_confirm) { | 802 if (args->GetBoolean(1, &dont_confirm) && dont_confirm) { |
615 AutoReset<bool> auto_reset(&ignore_changes_, true); | 803 AutoReset<bool> auto_reset(&ignore_changes_, true); |
616 ExtensionUninstallAccepted(); | 804 ExtensionUninstallAccepted(); |
617 } else { | 805 } else { |
| 806 // We don't use an AutoReset<bool> here as the uninstall dialog runs in a |
| 807 // different thread so it's not sync. |
| 808 uninstall_from_page_ = true; |
618 GetExtensionUninstallDialog()->ConfirmUninstall(extension); | 809 GetExtensionUninstallDialog()->ConfirmUninstall(extension); |
619 } | 810 } |
620 } | 811 } |
621 | 812 |
622 void AppLauncherHandler::HandleHideAppsPromo(const ListValue* args) { | 813 void AppLauncherHandler::HandleHideAppsPromo(const ListValue* args) { |
623 // If the user has intentionally hidden the promotion, we'll uninstall all the | 814 // If the user has intentionally hidden the promotion, we'll uninstall all the |
624 // default apps (we know the user hasn't installed any apps on their own at | 815 // default apps (we know the user hasn't installed any apps on their own at |
625 // this point, or the promotion wouldn't have been shown). | 816 // this point, or the promotion wouldn't have been shown). |
626 // TODO(estade): this isn't used right now as we sort out the future of the | 817 // TODO(estade): this isn't used right now as we sort out the future of the |
627 // apps promo on ntp4. | 818 // apps promo on ntp4. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 extension_service_->extension_prefs()->SetPageOrdinal(extension_id, | 880 extension_service_->extension_prefs()->SetPageOrdinal(extension_id, |
690 page_ordinal); | 881 page_ordinal); |
691 } | 882 } |
692 | 883 |
693 void AppLauncherHandler::HandlePromoSeen(const ListValue* args) { | 884 void AppLauncherHandler::HandlePromoSeen(const ListValue* args) { |
694 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, | 885 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, |
695 extension_misc::PROMO_SEEN, | 886 extension_misc::PROMO_SEEN, |
696 extension_misc::PROMO_BUCKET_BOUNDARY); | 887 extension_misc::PROMO_BUCKET_BOUNDARY); |
697 } | 888 } |
698 | 889 |
699 void AppLauncherHandler::HandleSaveAppPageName(const ListValue* args) { | 890 void AppLauncherHandler::HandleSaveAppsPageName(const ListValue* args) { |
700 string16 name; | 891 string16 name; |
701 CHECK(args->GetString(0, &name)); | 892 CHECK(args->GetString(0, &name)); |
702 | 893 |
703 double page_index; | 894 double page_index_double; |
704 CHECK(args->GetDouble(1, &page_index)); | 895 CHECK(args->GetDouble(1, &page_index_double)); |
| 896 size_t page_index = static_cast<size_t>(page_index_double); |
705 | 897 |
706 AutoReset<bool> auto_reset(&ignore_changes_, true); | 898 bool should_notify; |
| 899 CHECK(args->GetBoolean(2, &should_notify)); |
| 900 |
| 901 // There is logic within ExtensionPrefs::PageIntegerAsStringOrdinal() to give |
| 902 // us the next page ordinal if we're requesting an index that's greater than |
| 903 // what already exists (but only if it's +1 larger, which is fine for us). |
| 904 ExtensionPrefs* ext_prefs = extension_service_->extension_prefs(); |
| 905 StringOrdinal page_ordinal(ext_prefs->PageIntegerAsStringOrdinal(page_index)); |
| 906 CHECK(page_ordinal.IsValid()); |
| 907 |
| 908 // Don't ignore changes in same cases when we need to propagate the page |
| 909 // ordinal to the JS. |
| 910 AutoReset<bool> auto_reset(&ignore_changes_, !should_notify); |
| 911 |
707 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); | 912 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); |
708 ListPrefUpdate update(prefs, prefs::kNTPAppPageNames); | 913 DictionaryPrefUpdate update(prefs, prefs::kNTPAppsPageNames); |
709 ListValue* list = update.Get(); | 914 update.Get()->Set(page_ordinal.ToString(), Value::CreateStringValue(name)); |
710 list->Set(static_cast<size_t>(page_index), Value::CreateStringValue(name)); | |
711 } | 915 } |
712 | 916 |
713 void AppLauncherHandler::HandleGenerateAppForLink(const ListValue* args) { | 917 void AppLauncherHandler::HandleGenerateAppForLink(const ListValue* args) { |
714 std::string url; | 918 std::string url; |
715 CHECK(args->GetString(0, &url)); | 919 CHECK(args->GetString(0, &url)); |
716 GURL launch_url(url); | 920 GURL launch_url(url); |
717 | 921 |
718 string16 title; | 922 string16 title; |
719 CHECK(args->GetString(1, &title)); | 923 CHECK(args->GetString(1, &title)); |
720 | 924 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
822 return; | 1026 return; |
823 | 1027 |
824 StringValue app_id(highlight_app_id_); | 1028 StringValue app_id(highlight_app_id_); |
825 web_ui()->CallJavascriptFunction("ntp4.setAppToBeHighlighted", app_id); | 1029 web_ui()->CallJavascriptFunction("ntp4.setAppToBeHighlighted", app_id); |
826 highlight_app_id_.clear(); | 1030 highlight_app_id_.clear(); |
827 } | 1031 } |
828 | 1032 |
829 // static | 1033 // static |
830 void AppLauncherHandler::RegisterUserPrefs(PrefService* pref_service) { | 1034 void AppLauncherHandler::RegisterUserPrefs(PrefService* pref_service) { |
831 // TODO(csharp): We will want this to be a syncable preference instead. | 1035 // TODO(csharp): We will want this to be a syncable preference instead. |
832 pref_service->RegisterListPref(prefs::kNTPAppPageNames, | 1036 pref_service->RegisterDictionaryPref(prefs::kNTPAppsPageNames, |
| 1037 PrefService::UNSYNCABLE_PREF); |
| 1038 pref_service->RegisterListPref(prefs::kNTPAppsPageNamesOld, |
833 PrefService::UNSYNCABLE_PREF); | 1039 PrefService::UNSYNCABLE_PREF); |
834 } | 1040 } |
835 | 1041 |
836 // static | 1042 // static |
837 void AppLauncherHandler::RecordWebStoreLaunch(bool promo_active) { | 1043 void AppLauncherHandler::RecordWebStoreLaunch(bool promo_active) { |
838 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, | 1044 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, |
839 extension_misc::APP_LAUNCH_NTP_WEBSTORE, | 1045 extension_misc::APP_LAUNCH_NTP_WEBSTORE, |
840 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); | 1046 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
841 | 1047 |
842 if (!promo_active) return; | 1048 if (!promo_active) return; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
911 | 1117 |
912 // The extension can be uninstalled in another window while the UI was | 1118 // The extension can be uninstalled in another window while the UI was |
913 // showing. Do nothing in that case. | 1119 // showing. Do nothing in that case. |
914 const Extension* extension = | 1120 const Extension* extension = |
915 extension_service_->GetExtensionById(extension_id_prompting_, true); | 1121 extension_service_->GetExtensionById(extension_id_prompting_, true); |
916 if (!extension) | 1122 if (!extension) |
917 return; | 1123 return; |
918 | 1124 |
919 extension_service_->UninstallExtension(extension_id_prompting_, | 1125 extension_service_->UninstallExtension(extension_id_prompting_, |
920 false /* external_uninstall */, NULL); | 1126 false /* external_uninstall */, NULL); |
921 | 1127 CleanupAfterUninstall(); |
922 extension_id_prompting_ = ""; | |
923 } | 1128 } |
924 | 1129 |
925 void AppLauncherHandler::ExtensionUninstallCanceled() { | 1130 void AppLauncherHandler::ExtensionUninstallCanceled() { |
926 extension_id_prompting_ = ""; | 1131 CleanupAfterUninstall(); |
927 } | 1132 } |
928 | 1133 |
929 void AppLauncherHandler::InstallUIProceed() { | 1134 void AppLauncherHandler::InstallUIProceed() { |
930 // Do the re-enable work here. | 1135 // Do the re-enable work here. |
931 DCHECK(!extension_id_prompting_.empty()); | 1136 DCHECK(!extension_id_prompting_.empty()); |
932 | 1137 |
933 // The extension can be uninstalled in another window while the UI was | 1138 // The extension can be uninstalled in another window while the UI was |
934 // showing. Do nothing in that case. | 1139 // showing. Do nothing in that case. |
935 const Extension* extension = | 1140 const Extension* extension = |
936 extension_service_->GetExtensionById(extension_id_prompting_, true); | 1141 extension_service_->GetExtensionById(extension_id_prompting_, true); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
981 | 1186 |
982 void AppLauncherHandler::UninstallDefaultApps() { | 1187 void AppLauncherHandler::UninstallDefaultApps() { |
983 AppsPromo* apps_promo = extension_service_->apps_promo(); | 1188 AppsPromo* apps_promo = extension_service_->apps_promo(); |
984 const ExtensionIdSet& app_ids = apps_promo->old_default_apps(); | 1189 const ExtensionIdSet& app_ids = apps_promo->old_default_apps(); |
985 for (ExtensionIdSet::const_iterator iter = app_ids.begin(); | 1190 for (ExtensionIdSet::const_iterator iter = app_ids.begin(); |
986 iter != app_ids.end(); ++iter) { | 1191 iter != app_ids.end(); ++iter) { |
987 if (extension_service_->GetExtensionById(*iter, true)) | 1192 if (extension_service_->GetExtensionById(*iter, true)) |
988 extension_service_->UninstallExtension(*iter, false, NULL); | 1193 extension_service_->UninstallExtension(*iter, false, NULL); |
989 } | 1194 } |
990 } | 1195 } |
OLD | NEW |