Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3321)

Unified Diff: chrome/browser/ui/webui/ntp/app_launcher_handler.cc

Issue 8637001: [NTP4] Auto-deletion of empty apps panes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: removing bits for refactor Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/webui/ntp/app_launcher_handler.h ('k') | chrome/common/pref_names.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/webui/ntp/app_launcher_handler.cc
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index ae106c188ec8b38f3b7c26ec2a8c1ea3f0d6c914..1494922f5aa6ed4025c609c3560adecdd5bd62cd 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -4,9 +4,14 @@
#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
+#include <algorithm>
#include <string>
#include <vector>
+
+#include "base/json/json_writer.h"
+
+
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -32,12 +37,13 @@
#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
#include "chrome/browser/ui/webui/web_ui_util.h"
#include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/favicon_url.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/string_ordinal.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/web_apps.h"
#include "content/browser/webui/web_ui.h"
@@ -67,6 +73,29 @@ extension_misc::AppLaunchBucket ParseLaunchSource(
return bucket;
}
+enum PageListPrefMigrationUMABuckets {
+ NONE_REQUIRED = 0,
+ LIST_TO_DICTIONARY = 1,
+ BOUNDARY_BUCKET,
+};
+
+// Returns whether the original ordinal was valid.
+static void EnsurePageOrdinalIsValid(const Extension* extension,
+ ExtensionPrefs* ext_prefs) {
+ DCHECK(extension && ext_prefs);
+ StringOrdinal page_ordinal = ext_prefs->GetPageOrdinal(extension->id());
+
+ // Make sure every app has a page ordinal (some predate the page ordinal).
+ if (!page_ordinal.IsValid()) {
+ // If the ordinal lacking app is the webstore, put it on the first page.
+ page_ordinal = extension->id() == extension_misc::kWebStoreAppId ?
+ ext_prefs->CreateFirstAppPageOrdinal() :
+ ext_prefs->GetNaturalAppPageOrdinal();
+ LOG(ERROR) << "extension(" << extension->id() << ") didn't have a valid page ordinal! Creating one for it as " << page_ordinal.ToString();
+ ext_prefs->SetPageOrdinal(extension->id(), page_ordinal);
+ }
+}
+
} // namespace
AppLauncherHandler::AppInstallInfo::AppInstallInfo() {}
@@ -77,7 +106,8 @@ AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service)
: extension_service_(extension_service),
ignore_changes_(false),
attempted_bookmark_app_install_(false),
- has_loaded_apps_(false) {
+ has_loaded_apps_(false),
+ uninstall_from_page_(false) {
}
AppLauncherHandler::~AppLauncherHandler() {}
@@ -110,6 +140,9 @@ void AppLauncherHandler::CreateAppInfo(const Extension* extension,
const AppNotification* notification,
ExtensionService* service,
DictionaryValue* value) {
+ // Change this check if you'd like to pass a non-empty dictionary here.
+ DCHECK(value && value->empty());
+
bool enabled = service->IsExtensionEnabled(extension->id()) &&
!service->GetTerminatedExtension(extension->id());
bool icon_big_exists = true;
@@ -156,7 +189,6 @@ void AppLauncherHandler::CreateAppInfo(const Extension* extension,
extension->id() == extension_misc::kWebStoreAppId);
if (extension->HasAPIPermission(ExtensionAPIPermission::kAppNotifications)) {
- ExtensionPrefs* prefs = service->extension_prefs();
value->SetBoolean("notifications_disabled",
prefs->IsAppNotificationDisabled(extension->id()));
}
@@ -164,19 +196,9 @@ void AppLauncherHandler::CreateAppInfo(const Extension* extension,
if (notification)
value->Set("notification", SerializeNotification(*notification));
+ EnsurePageOrdinalIsValid(extension, prefs);
StringOrdinal page_ordinal = prefs->GetPageOrdinal(extension->id());
- if (!page_ordinal.IsValid()) {
- // Make sure every app has a page ordinal (some predate the page ordinal).
- // The webstore app should be on the first page.
- page_ordinal = extension->id() == extension_misc::kWebStoreAppId ?
- prefs->CreateFirstAppPageOrdinal() : prefs->GetNaturalAppPageOrdinal();
- prefs->SetPageOrdinal(extension->id(), page_ordinal);
- }
- // We convert the page_ordinal to an integer because the pages are referenced
- // from within an array in the javascript code, which can't be easily
- // changed to handle the StringOrdinal values, so we do the conversion here.
- int page_index = prefs->PageStringOrdinalAsInteger(page_ordinal);
- value->SetInteger("page_index", page_index >= 0 ? page_index : 0);
+ value->SetString("page_ordinal", page_ordinal.ToString());
StringOrdinal app_launch_ordinal =
prefs->GetAppLaunchOrdinal(extension->id());
@@ -196,6 +218,9 @@ void AppLauncherHandler::RegisterMessages() {
registrar_.Add(this, chrome::NOTIFICATION_APP_INSTALLED_TO_NTP,
content::Source<WebContents>(web_ui()->web_contents()));
+ web_ui()->RegisterMessageCallback("deleteEmptyAppsPage",
+ base::Bind(&AppLauncherHandler::HandleDeleteEmptyAppsPage,
+ base::Unretained(this)));
web_ui()->RegisterMessageCallback("getApps",
base::Bind(&AppLauncherHandler::HandleGetApps,
base::Unretained(this)));
@@ -223,8 +248,8 @@ void AppLauncherHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback("promoSeen",
base::Bind(&AppLauncherHandler::HandlePromoSeen,
base::Unretained(this)));
- web_ui()->RegisterMessageCallback("saveAppPageName",
- base::Bind(&AppLauncherHandler::HandleSaveAppPageName,
+ web_ui()->RegisterMessageCallback("saveAppsPageName",
+ base::Bind(&AppLauncherHandler::HandleSaveAppsPageName,
base::Unretained(this)));
web_ui()->RegisterMessageCallback("generateAppForLink",
base::Bind(&AppLauncherHandler::HandleGenerateAppForLink,
@@ -302,19 +327,41 @@ void AppLauncherHandler::Observe(int type,
content::Details<UnloadedExtensionInfo>(details)->reason ==
extension_misc::UNLOAD_REASON_UNINSTALL));
if (app_info.get()) {
+ scoped_ptr<base::FundamentalValue> from_page(
+ Value::CreateBooleanValue(uninstall_from_page_));
web_ui()->CallJavascriptFunction(
- "ntp4.appRemoved", *app_info, *uninstall_value);
+ "ntp4.appRemoved", *app_info, *uninstall_value, *from_page);
}
break;
}
- case chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED:
- // The promo may not load until a couple seconds after the first NTP view,
- // so we listen for the load notification and notify the NTP when ready.
- case chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED:
- // TODO(estade): try to get rid of this inefficient operation.
+ case chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED: {
+ DictionaryValue pages;
+ const ExtensionSet* extensions = extension_service_->extensions();
+ ExtensionPrefs* prefs = extension_service_->extension_prefs();
+ for (ExtensionSet::const_iterator it = extensions->begin();
+ it != extensions->end(); ++it) {
+ if (!IsAppExcludedFromList(*it)) {
+ std::string page_ordinal_string =
+ prefs->GetPageOrdinal((*it)->id()).ToString();
+ if (!pages.HasKey(page_ordinal_string))
+ pages.Set(page_ordinal_string, new DictionaryValue());
+ DictionaryValue* page;
+ CHECK(pages.GetDictionary(page_ordinal_string, &page));
+ page->SetString(prefs->GetAppLaunchOrdinal((*it)->id()).ToString(),
+ (*it)->id());
+ }
+ }
+ web_ui()->CallJavascriptFunction("ntp4.appsReordered", pages);
+ break;
+ }
+ case chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED: {
+ // The promo may not load until a couple seconds after the first NTP view,
+ // so we listen for the load notification and notify the NTP when ready.
HandleGetApps(NULL);
break;
+ }
case chrome::NOTIFICATION_PREF_CHANGED: {
+ LOG(ERROR) << "Pref changed!";
DictionaryValue dictionary;
FillAppDictionary(&dictionary);
web_ui()->CallJavascriptFunction("appsPrefChangeCallback", dictionary);
@@ -337,87 +384,179 @@ void AppLauncherHandler::Observe(int type,
}
}
-void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) {
- // CreateAppInfo and ClearPageOrdinal can change the extension prefs.
- AutoReset<bool> auto_reset(&ignore_changes_, true);
-
- ListValue* list = new ListValue();
- const ExtensionSet* extensions = extension_service_->extensions();
+void AppLauncherHandler::RemoveNonAppExtensionOrdinals(
+ const ExtensionSet* extensions) {
ExtensionSet::const_iterator it;
for (it = extensions->begin(); it != extensions->end(); ++it) {
const Extension* extension = *it;
- if (!IsAppExcludedFromList(extension)) {
- DictionaryValue* app_info = GetAppInfo(extension);
- list->Append(app_info);
- } else {
- // This is necessary because in some previous versions of chrome, we set a
- // page index for non-app extensions. Old profiles can persist this error,
- // and this fixes it. This caused GetNaturalAppPageIndex() to break
- // (see http://crbug.com/98325) before it was an ordinal value.
- ExtensionPrefs* prefs = extension_service_->extension_prefs();
- if (prefs->GetPageOrdinal(extension->id()).IsValid())
- prefs->ClearPageOrdinal(extension->id());
+ // Ensure any previous non-app extensions aren't showing / don't have a page
+ // ordinal or migrated page index. This is necessary because in some
+ // previous versions of chrome, we set a page index for non-app extensions.
+ // Old profiles can persist this error, and this fixes it. This caused
+ // GetNaturalAppPageIndex() to break (see http://crbug.com/98325) before it
+ // was an ordinal value.
+ if (IsAppExcludedFromList(extension)) {
+ ExtensionPrefs* ext_prefs = extension_service_->extension_prefs();
+ if (ext_prefs->GetPageOrdinal(extension->id()).IsValid())
+ ext_prefs->ClearPageOrdinal(extension->id());
}
}
+}
- extensions = extension_service_->disabled_extensions();
- for (it = extensions->begin(); it != extensions->end(); ++it) {
- if (!IsAppExcludedFromList(*it)) {
- DictionaryValue* app_info = new DictionaryValue();
- CreateAppInfo(*it,
- NULL,
- extension_service_,
- app_info);
- list->Append(app_info);
+void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) {
+ // CreateAppInfo and ClearPageOrdinal can change the extension prefs.
+ AutoReset<bool> auto_reset(&ignore_changes_, true);
+
+ RemoveNonAppExtensionOrdinals(extension_service_->extensions());
+
+ // Start NULL, CHECK() that it's not NULL after being populated with names.
+ DictionaryValue* apps_page_names = NULL;
+
+ // Get all the existing apps' page_ordinals, de-duped and sorted, and make
+ // sure we've got page names for all the existing pages (or populate with
+ // default). If there's a page without any apps on it, delete that pref.
+ scoped_ptr<std::vector<std::string> > page_ordinals(PageOrdinalsFromApps());
+
+ // Most of the time we probably won't need to update, so let's only do this
+ // when something changes (during migration or an edge case like mentioned
+ // above when the page names pref doesn't match the apps' info).
+ bool update_required = false;
+
+ // If the legacy preference exists, migrate it from a list to a dictionary.
+ // TODO(dbeam): Remove migration when UMA hits sufficiently small number.
+ PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
+ if (prefs->HasPrefPath(prefs::kNTPAppsPageNamesOld)) {
+ LOG(ERROR) << "Migrating from list to dict for page names required!";
+ apps_page_names = new DictionaryValue();
+ scoped_ptr<ListValue> apps_page_names_list(
+ prefs->GetList(prefs::kNTPAppsPageNamesOld)->DeepCopy());
+ string16 default_page_name(
+ l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME));
+ for (size_t i = 0; i < page_ordinals->size(); ++i) {
+ if (i >= apps_page_names_list->GetSize()) {
+ apps_page_names->Set(page_ordinals->at(i),
+ Value::CreateStringValue(default_page_name));
+ } else {
+ Value* name;
+ CHECK(apps_page_names_list->Get(i, &name));
+ apps_page_names->Set(page_ordinals->at(i), name->DeepCopy());
+ }
}
+ // If there were extra entries just ignore, we're deleting whole preference.
+ prefs->ClearPref(prefs::kNTPAppsPageNamesOld);
+ update_required = true;
+ UMA_HISTOGRAM_ENUMERATION("NewTabPage.PageNamesPrefMigration",
+ LIST_TO_DICTIONARY, BOUNDARY_BUCKET);
+ } else {
+ LOG(ERROR) << "No migration required!";
+ apps_page_names =
+ prefs->GetDictionary(prefs::kNTPAppsPageNames)->DeepCopy();
+ update_required = SyncPageNamesToApps(apps_page_names);
+ // Log this to more easily track how many folks are done migrating prefs.
+ UMA_HISTOGRAM_ENUMERATION("NewTabPage.PageNamesPrefMigration",
+ NONE_REQUIRED, BOUNDARY_BUCKET);
+ }
+ // There should always be something in this pref (as there should always be at
+ // least one app which requires a page to live on).
+ CHECK(apps_page_names && !apps_page_names->empty());
+
+ if (update_required) {
+ LOG(ERROR) << "Something about page names changed, updating!";
+ scoped_ptr<DictionaryValue> page_names_copy(apps_page_names->DeepCopy());
+ DictionaryPrefUpdate update(prefs, prefs::kNTPAppsPageNames);
+ update.Get()->Swap(page_names_copy.get());
}
- extensions = extension_service_->terminated_extensions();
- for (it = extensions->begin(); it != extensions->end(); ++it) {
+ std::string json;
+ base::JSONWriter::Write(apps_page_names, false, &json);
+ LOG(ERROR) << apps_page_names->size() << ", " << json;
+
+ // Create a dictionary structured by pages and app ordinals, like this:
+ // {
+ // "<page_ordinal>": {
+ // "name": <page_name>,
+ // "apps": {
+ // <app_launch_ordinal>": { <app_info> },
+ // ...
+ // }
+ // ...
+ // },
+ // ...
+ // }
+ DictionaryValue* apps_pages = new DictionaryValue();
+
+ scoped_ptr<const ExtensionSet> installed_extensions(
+ extension_service_->GetAllInstalledExtensions());
+
+ for (ExtensionSet::const_iterator it = installed_extensions->begin();
+ it != installed_extensions->end(); ++it) {
if (!IsAppExcludedFromList(*it)) {
DictionaryValue* app_info = new DictionaryValue();
- CreateAppInfo(*it,
- NULL,
- extension_service_,
- app_info);
- list->Append(app_info);
- }
- }
+ CreateAppInfo(*it, NULL, extension_service_, app_info);
- dictionary->Set("apps", list);
+ std::string page_ordinal;
+ DCHECK(app_info->GetString("page_ordinal", &page_ordinal));
+ LOG(ERROR) << "App had page_ordinal: " << page_ordinal;
- // TODO(estade): remove these settings when the old NTP is removed. The new
- // NTP does it in js.
-#if defined(OS_MACOSX)
- // App windows are not yet implemented on mac.
- dictionary->SetBoolean("disableAppWindowLaunch", true);
- dictionary->SetBoolean("disableCreateAppShortcut", true);
-#endif
+ if (!apps_pages->HasKey(page_ordinal))
+ apps_pages->Set(page_ordinal, new DictionaryValue());
-#if defined(OS_CHROMEOS)
- // Making shortcut does not make sense on ChromeOS because it does not have
- // a desktop.
- dictionary->SetBoolean("disableCreateAppShortcut", true);
-#endif
+ DictionaryValue* page;
+ DCHECK(apps_pages->GetDictionary(page_ordinal, &page));
- dictionary->SetBoolean(
- "showLauncher",
- extension_service_->apps_promo()->ShouldShowAppLauncher(
- extension_service_->GetAppIds()));
+ if (!page->HasKey("apps"))
+ page->Set("apps", new DictionaryValue());
- PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
- const ListValue* app_page_names = prefs->GetList(prefs::kNTPAppPageNames);
- if (!app_page_names || !app_page_names->GetSize()) {
- ListPrefUpdate update(prefs, prefs::kNTPAppPageNames);
- ListValue* list = update.Get();
- list->Set(0, Value::CreateStringValue(
- l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME)));
- dictionary->Set("appPageNames",
- static_cast<ListValue*>(list->DeepCopy()));
- } else {
- dictionary->Set("appPageNames",
- static_cast<ListValue*>(app_page_names->DeepCopy()));
+ if (!page->HasKey("name")) {
+ std::string page_name;
+ DCHECK(apps_page_names->GetString(page_ordinal, &page_name));
+ page->Set("name", Value::CreateStringValue(page_name));
+ }
+
+ DictionaryValue* apps;
+ DCHECK(page->GetDictionary("apps", &apps));
+
+ std::string app_launch_ordinal;
+ DCHECK(app_info->GetString("app_launch_ordinal", &app_launch_ordinal));
+
+ DCHECK(!apps->HasKey(app_launch_ordinal));
+ apps->Set(app_launch_ordinal, app_info);
+ }
}
+ CHECK(apps_pages->size() >= 1);
+ dictionary->Set("appsPages", apps_pages);
+}
+
+bool AppLauncherHandler::SyncPageNamesToApps(DictionaryValue* page_names) {
+ string16 default_page_name =
+ l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME);
+ bool value_changed = false;
+ // Get all the unique page ordinals that the current set of apps has and if no
+ // page name exists for that page yet, create one with the default value.
+ scoped_ptr<std::vector<std::string> > ordinals(PageOrdinalsFromApps());
+ for (std::vector<std::string>::const_iterator it = ordinals->begin();
+ it != ordinals->end(); ++it) {
+ if (!page_names->HasKey(*it)) {
+ LOG(ERROR) << "Found new page ordinal, " << *it << ", setting it to default page name! (" << default_page_name << ")";
+ page_names->SetString(*it, default_page_name);
+ value_changed = true;
+ }
+ }
+ // Make a copy to avoid invalidating our iterator if a key is deleted.
+ scoped_ptr<DictionaryValue> page_names_copy(page_names->DeepCopy());
+ // Look for extraneous pages that no longer have apps on them.
+ for (DictionaryValue::key_iterator it = page_names->begin_keys();
+ it != page_names->end_keys(); ++it) {
+ if (std::find(ordinals->begin(), ordinals->end(), *it) == ordinals->end()) {
+ LOG(ERROR) << "Found left over page ordinal, " << *it << ", deleting!";
+ DCHECK(page_names_copy->Remove(*it, NULL));
+ value_changed = true;
+ }
+ }
+ // Swap with the possibly affected dictionary.
+ page_names->Swap(page_names_copy.get());
+ // Tell the caller whether anything changed in this method.
+ return value_changed;
}
DictionaryValue* AppLauncherHandler::GetAppInfo(const Extension* extension) {
@@ -433,6 +572,23 @@ DictionaryValue* AppLauncherHandler::GetAppInfo(const Extension* extension) {
return app_info;
}
+std::vector<std::string>* AppLauncherHandler::PageOrdinalsFromApps() {
+ std::vector<std::string>* pages = new std::vector<std::string>();
+ const ExtensionSet* extensions = extension_service_->extensions();
+ ExtensionPrefs* ext_prefs = extension_service_->extension_prefs();
+ for (ExtensionSet::const_iterator it = extensions->begin();
+ it != extensions->end(); ++it) {
+ if (!IsAppExcludedFromList(*it)) {
+ EnsurePageOrdinalIsValid(*it, ext_prefs);
+ std::string ordinal(ext_prefs->GetPageOrdinal((*it)->id()).ToString());
+ if (std::find(pages->begin(), pages->end(), ordinal) == pages->end())
+ pages->push_back(ordinal);
+ }
+ }
+ std::sort(pages->begin(), pages->end());
+ return pages;
+}
+
void AppLauncherHandler::FillPromoDictionary(DictionaryValue* dictionary) {
AppsPromo::PromoData data = AppsPromo::GetPromo();
dictionary->SetString("promoHeader", data.header);
@@ -442,6 +598,38 @@ void AppLauncherHandler::FillPromoDictionary(DictionaryValue* dictionary) {
dictionary->SetString("promoExpire", data.expire);
}
+void AppLauncherHandler::HandleDeleteEmptyAppsPage(const ListValue* args) {
+ std::string page_ordinal;
+ CHECK(args->GetString(0, &page_ordinal));
+
+ AutoReset<bool> auto_reset(&ignore_changes_, true);
+
+ PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
+ const DictionaryValue* dict = prefs->GetDictionary(prefs::kNTPAppsPageNames);
+ std::string value;
+ DCHECK(dict->GetString(page_ordinal, &value));
+
+ LOG(ERROR) << "Its value is: " << value;
+
+ // Ensure the page we're deleting is empty.
+ scoped_ptr<std::vector<std::string> > pages(PageOrdinalsFromApps());
+ DCHECK(std::find(pages->begin(), pages->end(), page_ordinal) == pages->end());
+
+ DictionaryPrefUpdate update(prefs, prefs::kNTPAppsPageNames);
+ DCHECK(update.Get()->Remove(page_ordinal, NULL));
+
+ dict = prefs->GetDictionary(prefs::kNTPAppsPageNames);
+
+ std::string json;
+ base::JSONWriter::Write(dict, false, &json);
+ LOG(ERROR) << "now is: " << dict->size() << ", " << json;
+}
+
+void AppLauncherHandler::CleanupAfterUninstall() {
+ uninstall_from_page_ = false;
+ extension_id_prompting_ = "";
+}
+
void AppLauncherHandler::HandleGetApps(const ListValue* args) {
DictionaryValue dictionary;
@@ -482,7 +670,7 @@ void AppLauncherHandler::HandleGetApps(const ListValue* args) {
pref_change_registrar_.Init(
extension_service_->extension_prefs()->pref_service());
pref_change_registrar_.Add(ExtensionPrefs::kExtensionsPref, this);
- pref_change_registrar_.Add(prefs::kNTPAppPageNames, this);
+ pref_change_registrar_.Add(prefs::kNTPAppsPageNames, this);
registrar_.Add(this, chrome::NOTIFICATION_APP_NOTIFICATION_STATE_CHANGED,
content::Source<Profile>(profile));
@@ -615,6 +803,9 @@ void AppLauncherHandler::HandleUninstallApp(const ListValue* args) {
AutoReset<bool> auto_reset(&ignore_changes_, true);
ExtensionUninstallAccepted();
} else {
+ // We don't use an AutoReset<bool> here as the uninstall dialog runs in a
+ // different thread so it's not sync.
+ uninstall_from_page_ = true;
GetExtensionUninstallDialog()->ConfirmUninstall(extension);
}
}
@@ -696,18 +887,31 @@ void AppLauncherHandler::HandlePromoSeen(const ListValue* args) {
extension_misc::PROMO_BUCKET_BOUNDARY);
}
-void AppLauncherHandler::HandleSaveAppPageName(const ListValue* args) {
+void AppLauncherHandler::HandleSaveAppsPageName(const ListValue* args) {
string16 name;
CHECK(args->GetString(0, &name));
- double page_index;
- CHECK(args->GetDouble(1, &page_index));
+ double page_index_double;
+ CHECK(args->GetDouble(1, &page_index_double));
+ size_t page_index = static_cast<size_t>(page_index_double);
+
+ bool should_notify;
+ CHECK(args->GetBoolean(2, &should_notify));
+
+ // There is logic within ExtensionPrefs::PageIntegerAsStringOrdinal() to give
+ // us the next page ordinal if we're requesting an index that's greater than
+ // what already exists (but only if it's +1 larger, which is fine for us).
+ ExtensionPrefs* ext_prefs = extension_service_->extension_prefs();
+ StringOrdinal page_ordinal(ext_prefs->PageIntegerAsStringOrdinal(page_index));
+ CHECK(page_ordinal.IsValid());
+
+ // Don't ignore changes in same cases when we need to propagate the page
+ // ordinal to the JS.
+ AutoReset<bool> auto_reset(&ignore_changes_, !should_notify);
- AutoReset<bool> auto_reset(&ignore_changes_, true);
PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
- ListPrefUpdate update(prefs, prefs::kNTPAppPageNames);
- ListValue* list = update.Get();
- list->Set(static_cast<size_t>(page_index), Value::CreateStringValue(name));
+ DictionaryPrefUpdate update(prefs, prefs::kNTPAppsPageNames);
+ update.Get()->Set(page_ordinal.ToString(), Value::CreateStringValue(name));
}
void AppLauncherHandler::HandleGenerateAppForLink(const ListValue* args) {
@@ -829,7 +1033,9 @@ void AppLauncherHandler::SetAppToBeHighlighted() {
// static
void AppLauncherHandler::RegisterUserPrefs(PrefService* pref_service) {
// TODO(csharp): We will want this to be a syncable preference instead.
- pref_service->RegisterListPref(prefs::kNTPAppPageNames,
+ pref_service->RegisterDictionaryPref(prefs::kNTPAppsPageNames,
+ PrefService::UNSYNCABLE_PREF);
+ pref_service->RegisterListPref(prefs::kNTPAppsPageNamesOld,
PrefService::UNSYNCABLE_PREF);
}
@@ -918,12 +1124,11 @@ void AppLauncherHandler::ExtensionUninstallAccepted() {
extension_service_->UninstallExtension(extension_id_prompting_,
false /* external_uninstall */, NULL);
-
- extension_id_prompting_ = "";
+ CleanupAfterUninstall();
}
void AppLauncherHandler::ExtensionUninstallCanceled() {
- extension_id_prompting_ = "";
+ CleanupAfterUninstall();
}
void AppLauncherHandler::InstallUIProceed() {
« no previous file with comments | « chrome/browser/ui/webui/ntp/app_launcher_handler.h ('k') | chrome/common/pref_names.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698