summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-30 13:40:38 +0000
committerjoaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-30 13:40:38 +0000
commit1b8acdba23bba89eb14877c3964415eb0f3b8dfb (patch)
tree140104e98f12672576b8060ae2570d92a57ac9b0
parentf3b2b8d149f79bcbc3f6f89115654e69bf7818fe (diff)
downloadchromium_src-1b8acdba23bba89eb14877c3964415eb0f3b8dfb.zip
chromium_src-1b8acdba23bba89eb14877c3964415eb0f3b8dfb.tar.gz
chromium_src-1b8acdba23bba89eb14877c3964415eb0f3b8dfb.tar.bz2
Added a policy to manage mobile bookmarks on Android.
This policy controls a "Managed bookmarks" folder within the "Mobile bookmarks", which isn't part of the user's boomarks model. These bookmarks can't be edited, and are not synced to the user account. BUG=265643 R=pneubeck@chromium.org, tedchoc@chromium.org Review URL: https://codereview.chromium.org/21121004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@214342 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd9
-rw-r--r--chrome/app/policy/policy_templates.json34
-rw-r--r--chrome/browser/policy/configuration_policy_handler_android.cc103
-rw-r--r--chrome/browser/policy/configuration_policy_handler_android.h39
-rw-r--r--chrome/browser/policy/configuration_policy_handler_list.cc8
-rw-r--r--chrome/browser/policy/profile_policy_connector_factory.cc9
-rw-r--r--chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc187
-rw-r--r--chrome/browser/ui/webui/ntp/android/bookmarks_handler.h29
-rw-r--r--chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.cc96
-rw-r--r--chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.h56
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_browser_ui.gypi2
-rw-r--r--chrome/common/pref_names.cc5
-rw-r--r--chrome/common/pref_names.h1
-rw-r--r--chrome/test/data/policy/policy_test_cases.json3
-rwxr-xr-xchrome/tools/build/generate_policy_source.py18
16 files changed, 509 insertions, 92 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e52871b..e64556f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6148,6 +6148,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_POLICY_UNKNOWN" desc="Text displayed in the status column when a policy name is not recognized.">
Unknown policy.
</message>
+ <message name="IDS_POLICY_INVALID_BOOKMARK" desc="Text displayed in the status column when an entry of the ManagedBookmarks policy is not a valid bookmark.">
+ Ignored invalid bookmark at index <ph name="ENTRY_INDEX">$1<ex>3</ex></ph>
+ </message>
<!-- chrome://policy -->
<message name="IDS_POLICY_TITLE" desc="Page title and the title of the section that lists policies.">
@@ -6236,6 +6239,12 @@ Keep your key file in a safe place. You will need it to create new versions of y
Mandatory
</message>
+ <if expr="is_android">
+ <message name="IDS_POLICY_MANAGED_BOOKMARKS" desc="Mobile: name of the managed bookmarks folder">
+ Managed bookmarks
+ </message>
+ </if>
+
<!-- about:flags -->
<message name="IDS_FLAGS_LONG_TITLE" desc="Long version of the title for the about:flags page.">
Careful, these experiments may bite
diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json
index 86bc3ac..3a32920 100644
--- a/chrome/app/policy/policy_templates.json
+++ b/chrome/app/policy/policy_templates.json
@@ -5253,6 +5253,40 @@
},
],
},
+ # TODO(joaodasilva): replace the 'dict' type with a more generic
+ # 'json' type. The actual schema type for this should be 'array'.
+ {
+ 'name': 'ManagedBookmarks',
+ 'type': 'dict',
+ 'schema': {
+ 'type': 'object',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'name': { 'type': 'string' },
+ 'url': { 'type': 'string' },
+ },
+ },
+ },
+ 'supported_on': ['android:30-'],
+ 'features': {
+ 'dynamic_refresh': True,
+ 'per_profile': True,
+ },
+ 'future': True,
+ 'example_value': { "name": "Google", "url": "google.com" },
+ 'id': 227,
+ 'caption': '''Managed Bookmarks''',
+ 'desc': '''Configures a list of managed bookmarks.
+
+ The policy is a list of bookmarks, and each bookmark is a dictionary containing the bookmark "name" and target "url".
+
+ These bookmarks are placed in a Managed bookmarks folder inside the Mobile bookmarks. These bookmarks can't be modified by the user.
+
+ When this policy is set then the Managed bookmarks are the default folder opened when the bookmarks view is opened in Chrome.
+
+ Managed bookmarks are not synced to the user account.''',
+ },
],
'messages': {
# Messages that are not associated to any policies.
diff --git a/chrome/browser/policy/configuration_policy_handler_android.cc b/chrome/browser/policy/configuration_policy_handler_android.cc
new file mode 100644
index 0000000..3dca35f
--- /dev/null
+++ b/chrome/browser/policy/configuration_policy_handler_android.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/policy/configuration_policy_handler_android.h"
+
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/net/url_fixer_upper.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+#include "url/gurl.h"
+
+namespace policy {
+
+namespace {
+
+bool GetBookmark(const base::Value& value,
+ std::string* name,
+ std::string* url) {
+ const base::DictionaryValue* dict = NULL;
+ if (!value.GetAsDictionary(&dict))
+ return false;
+ std::string url_string;
+ if (!dict->GetStringWithoutPathExpansion(ManagedBookmarksPolicyHandler::kName,
+ name) ||
+ !dict->GetStringWithoutPathExpansion(ManagedBookmarksPolicyHandler::kUrl,
+ &url_string)) {
+ return false;
+ }
+ GURL gurl = URLFixerUpper::FixupURL(url_string, "");
+ if (!gurl.is_valid())
+ return false;
+ *url = gurl.spec();
+ return true;
+}
+
+} // namespace
+
+const char ManagedBookmarksPolicyHandler::kName[] = "name";
+const char ManagedBookmarksPolicyHandler::kUrl[] = "url";
+
+ManagedBookmarksPolicyHandler::ManagedBookmarksPolicyHandler()
+ : TypeCheckingPolicyHandler(key::kManagedBookmarks,
+ base::Value::TYPE_LIST) {}
+
+ManagedBookmarksPolicyHandler::~ManagedBookmarksPolicyHandler() {}
+
+bool ManagedBookmarksPolicyHandler::CheckPolicySettings(
+ const PolicyMap& policies,
+ PolicyErrorMap* errors) {
+ const base::Value* value = NULL;
+ if (!CheckAndGetValue(policies, errors, &value))
+ return false;
+
+ if (!value)
+ return true;
+
+ const base::ListValue* list = NULL;
+ value->GetAsList(&list);
+ DCHECK(list);
+
+ for (base::ListValue::const_iterator it = list->begin();
+ it != list->end(); ++it) {
+ std::string name;
+ std::string url;
+ if (!*it || !GetBookmark(**it, &name, &url)) {
+ size_t index = it - list->begin();
+ errors->AddError(policy_name(), IDS_POLICY_INVALID_BOOKMARK, index);
+ }
+ }
+
+ return true;
+}
+
+void ManagedBookmarksPolicyHandler::ApplyPolicySettings(
+ const PolicyMap& policies,
+ PrefValueMap* prefs) {
+ const base::Value* value = policies.GetValue(policy_name());
+ const base::ListValue* list = NULL;
+ if (!value || !value->GetAsList(&list))
+ return;
+
+ base::ListValue* bookmarks = new base::ListValue();
+ for (base::ListValue::const_iterator it = list->begin();
+ it != list->end(); ++it) {
+ std::string name;
+ std::string url;
+ if (*it && GetBookmark(**it, &name, &url)) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetString(kName, name);
+ dict->SetString(kUrl, url);
+ bookmarks->Append(dict);
+ }
+ }
+
+ prefs->SetValue(prefs::kManagedBookmarks, bookmarks);
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_handler_android.h b/chrome/browser/policy/configuration_policy_handler_android.h
new file mode 100644
index 0000000..b0328d9
--- /dev/null
+++ b/chrome/browser/policy/configuration_policy_handler_android.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_HANDLER_ANDROID_H_
+#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_HANDLER_ANDROID_H_
+
+#include <string>
+
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+namespace base {
+class Value;
+}
+
+namespace policy {
+
+// Handles the ManagedBookmarks policy.
+class ManagedBookmarksPolicyHandler : public TypeCheckingPolicyHandler {
+ public:
+ static const char kName[];
+ static const char kUrl[];
+
+ ManagedBookmarksPolicyHandler();
+ virtual ~ManagedBookmarksPolicyHandler();
+
+ // ConfigurationPolicyHandler methods:
+ virtual bool CheckPolicySettings(const PolicyMap& policies,
+ PolicyErrorMap* errors) OVERRIDE;
+ virtual void ApplyPolicySettings(const PolicyMap& policies,
+ PrefValueMap* prefs) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ManagedBookmarksPolicyHandler);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_HANDLER_ANDROID_H_
diff --git a/chrome/browser/policy/configuration_policy_handler_list.cc b/chrome/browser/policy/configuration_policy_handler_list.cc
index fec7efa..47f3a7b 100644
--- a/chrome/browser/policy/configuration_policy_handler_list.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list.cc
@@ -23,6 +23,10 @@
#include "chromeos/dbus/power_policy_controller.h"
#endif // defined(OS_CHROMEOS)
+#if defined(OS_ANDROID)
+#include "chrome/browser/policy/configuration_policy_handler_android.h"
+#endif // defined(OS_ANDROID)
+
namespace policy {
namespace {
@@ -570,6 +574,10 @@ ConfigurationPolicyHandlerList::ConfigurationPolicyHandlerList() {
NULL,
0, ash::MAGNIFIER_FULL, false));
#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_ANDROID)
+ handlers_.push_back(new ManagedBookmarksPolicyHandler());
+#endif
}
ConfigurationPolicyHandlerList::~ConfigurationPolicyHandlerList() {
diff --git a/chrome/browser/policy/profile_policy_connector_factory.cc b/chrome/browser/policy/profile_policy_connector_factory.cc
index 774208c..9d05260 100644
--- a/chrome/browser/policy/profile_policy_connector_factory.cc
+++ b/chrome/browser/policy/profile_policy_connector_factory.cc
@@ -7,14 +7,14 @@
#include "base/logging.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+#include "components/user_prefs/pref_registry_syncable.h"
#if defined(ENABLE_CONFIGURATION_POLICY)
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
-#include "chrome/common/pref_names.h"
-#include "components/user_prefs/pref_registry_syncable.h"
#else
#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
#endif
@@ -116,6 +116,11 @@ void ProfilePolicyConnectorFactory::RegisterProfilePrefs(
false,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
#endif
+#if defined(OS_ANDROID)
+ registry->RegisterListPref(
+ prefs::kManagedBookmarks,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+#endif
}
void ProfilePolicyConnectorFactory::SetEmptyTestingFactory(
diff --git a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc
index 3981a7c..a6a9683 100644
--- a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc
+++ b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc
@@ -33,31 +33,6 @@ namespace {
static const char* kParentIdParam = "parent_id";
static const char* kNodeIdParam = "node_id";
-// Parses a bookmark ID passed back from the NTP. The IDs differ from the
-// normal int64 bookmark ID because we prepend a "p" if the ID represents a
-// partner bookmark.
-bool ParseNtpBookmarkId(const ListValue* args,
- int64* out_id,
- bool* out_is_partner) {
- if (!args || args->empty())
- return false;
-
- std::string string_id;
- if (!args->GetString(0, &string_id))
- return false;
-
- if (string_id.empty())
- return false;
-
- if (StartsWithASCII(string_id, "p", true)) {
- *out_is_partner = true;
- return base::StringToInt64(string_id.substr(1), out_id);
- }
-
- *out_is_partner = false;
- return base::StringToInt64(string_id, out_id);
-}
-
std::string BookmarkTypeAsString(BookmarkNode::Type type) {
switch (type) {
case BookmarkNode::URL:
@@ -99,6 +74,9 @@ BookmarksHandler::~BookmarksHandler() {
if (partner_bookmarks_shim_)
partner_bookmarks_shim_->RemoveObserver(this);
+
+ if (managed_bookmarks_shim_)
+ managed_bookmarks_shim_->RemoveObserver(this);
}
void BookmarksHandler::RegisterMessages() {
@@ -125,6 +103,9 @@ void BookmarksHandler::RegisterMessages() {
partner_bookmarks_shim_->AddObserver(this);
}
+ managed_bookmarks_shim_.reset(new ManagedBookmarksShim(profile->GetPrefs()));
+ managed_bookmarks_shim_->AddObserver(this);
+
// Register ourselves as the handler for the bookmark javascript callbacks.
web_ui()->RegisterMessageCallback("getBookmarks",
base::Bind(&BookmarksHandler::HandleGetBookmarks,
@@ -159,24 +140,20 @@ void BookmarksHandler::HandleGetBookmarks(const ListValue* args) {
if (!partner_bookmarks_shim_->IsLoaded())
return; // is handled with a PartnerShimLoaded() callback
- int64 id;
- bool is_partner;
- if (ParseNtpBookmarkId(args, &id, &is_partner))
- QueryBookmarkFolder(id, is_partner);
+ const BookmarkNode* node = GetNodeByID(args);
+ if (node)
+ QueryBookmarkFolder(node);
else
QueryInitialBookmarks();
}
void BookmarksHandler::HandleDeleteBookmark(const ListValue* args) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- int64 id;
- bool is_partner;
- if (!ParseNtpBookmarkId(args, &id, &is_partner))
+ const BookmarkNode* node = GetNodeByID(args);
+ if (!node)
return;
- const BookmarkNode* node =
- partner_bookmarks_shim_->GetNodeByID(id, is_partner);
- if (!partner_bookmarks_shim_->IsBookmarkEditable(node)) {
+ if (!IsEditable(node)) {
NOTREACHED();
return;
}
@@ -187,14 +164,11 @@ void BookmarksHandler::HandleDeleteBookmark(const ListValue* args) {
void BookmarksHandler::HandleEditBookmark(const ListValue* args) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- int64 id;
- bool is_partner;
- if (!ParseNtpBookmarkId(args, &id, &is_partner))
+ const BookmarkNode* node = GetNodeByID(args);
+ if (!node)
return;
- const BookmarkNode* node =
- partner_bookmarks_shim_->GetNodeByID(id, is_partner);
- if (!partner_bookmarks_shim_->IsBookmarkEditable(node)) {
+ if (!IsEditable(node)) {
NOTREACHED();
return;
}
@@ -205,8 +179,12 @@ void BookmarksHandler::HandleEditBookmark(const ListValue* args) {
}
std::string BookmarksHandler::GetBookmarkIdForNtp(const BookmarkNode* node) {
- return (partner_bookmarks_shim_->IsPartnerBookmark(node) ? "p" : "") +
- Int64ToString(node->id());
+ std::string prefix;
+ if (partner_bookmarks_shim_->IsPartnerBookmark(node))
+ prefix = "p";
+ else if (managed_bookmarks_shim_->IsManagedBookmark(node))
+ prefix = "m";
+ return prefix + Int64ToString(node->id());
}
void BookmarksHandler::SetParentInBookmarksResult(const BookmarkNode* parent,
@@ -221,17 +199,7 @@ void BookmarksHandler::PopulateBookmark(const BookmarkNode* node,
DictionaryValue* filler_value = new DictionaryValue();
filler_value->SetString("title", node->GetTitle());
-
- // Mark reserved system nodes and partner bookmarks as uneditable.
- // Also mark them uneditable when it is disabled by a preference
- // (which can be forced by a policy).
- // (i.e. the bookmark bar along with the "Other Bookmarks" folder).
- const PrefService* pref = Profile::FromBrowserContext(
- web_ui()->GetWebContents()->GetBrowserContext())->GetPrefs();
- bool editable = partner_bookmarks_shim_->IsBookmarkEditable(node) &&
- pref->GetBoolean(prefs::kEditBookmarksEnabled);
- filler_value->SetBoolean("editable", editable);
-
+ filler_value->SetBoolean("editable", IsEditable(node));
if (node->is_url()) {
filler_value->SetBoolean("folder", false);
filler_value->SetString("url", node->url().spec());
@@ -248,6 +216,14 @@ void BookmarksHandler::PopulateBookmarksInFolder(
DictionaryValue* result) {
ListValue* bookmarks = new ListValue();
+ // If this is the Mobile bookmarks folder then add the "Managed bookmarks"
+ // folder first, so that it's the first entry.
+ if (bookmark_model_ && folder == bookmark_model_->mobile_node() &&
+ managed_bookmarks_shim_->HasManagedBookmarks()) {
+ PopulateBookmark(managed_bookmarks_shim_->GetManagedBookmarksRoot(),
+ bookmarks);
+ }
+
for (int i = 0; i < folder->child_count(); i++) {
const BookmarkNode* bookmark= folder->GetChild(i);
PopulateBookmark(bookmark, bookmarks);
@@ -262,34 +238,30 @@ void BookmarksHandler::PopulateBookmarksInFolder(
}
ListValue* folder_hierarchy = new ListValue();
- const BookmarkNode* parent = partner_bookmarks_shim_->GetParentOf(folder);
+ const BookmarkNode* parent = GetParentOf(folder);
while (parent != NULL) {
DictionaryValue* hierarchy_entry = new DictionaryValue();
- if (partner_bookmarks_shim_->IsRootNode(parent))
+ if (IsRoot(parent))
hierarchy_entry->SetBoolean("root", true);
hierarchy_entry->SetString("title", parent->GetTitle());
hierarchy_entry->SetString("id", GetBookmarkIdForNtp(parent));
folder_hierarchy->Append(hierarchy_entry);
- parent = partner_bookmarks_shim_->GetParentOf(parent);
+ parent = GetParentOf(parent);
}
result->SetString("title", folder->GetTitle());
result->SetString("id", GetBookmarkIdForNtp(folder));
- result->SetBoolean("root", partner_bookmarks_shim_->IsRootNode(folder));
+ result->SetBoolean("root", IsRoot(folder));
result->Set("bookmarks", bookmarks);
result->Set("hierarchy", folder_hierarchy);
}
-void BookmarksHandler::QueryBookmarkFolder(const int64& folder_id,
- bool is_partner_bookmark) {
- DCHECK(partner_bookmarks_shim_ != NULL);
- const BookmarkNode* bookmarks =
- partner_bookmarks_shim_->GetNodeByID(folder_id, is_partner_bookmark);
- if (bookmarks) {
+void BookmarksHandler::QueryBookmarkFolder(const BookmarkNode* node) {
+ if (node->is_folder()) {
DictionaryValue result;
- PopulateBookmarksInFolder(bookmarks, &result);
+ PopulateBookmarksInFolder(node, &result);
SendResult(result);
} else {
// If we receive an ID that no longer maps to a bookmark folder, just
@@ -301,12 +273,17 @@ void BookmarksHandler::QueryBookmarkFolder(const int64& folder_id,
void BookmarksHandler::QueryInitialBookmarks() {
DictionaryValue result;
DCHECK(partner_bookmarks_shim_ != NULL);
- PopulateBookmarksInFolder(
- // We have to go to the partner Root if it exists
- partner_bookmarks_shim_->HasPartnerBookmarks() ?
- partner_bookmarks_shim_->GetPartnerBookmarksRoot() :
- bookmark_model_->mobile_node(),
- &result);
+
+ if (managed_bookmarks_shim_->HasManagedBookmarks()) {
+ PopulateBookmarksInFolder(
+ managed_bookmarks_shim_->GetManagedBookmarksRoot(), &result);
+ } else if (partner_bookmarks_shim_->HasPartnerBookmarks()) {
+ PopulateBookmarksInFolder(
+ partner_bookmarks_shim_->GetPartnerBookmarksRoot(), &result);
+ } else {
+ PopulateBookmarksInFolder(bookmark_model_->mobile_node(), &result);
+ }
+
SendResult(result);
}
@@ -326,6 +303,10 @@ void BookmarksHandler::ShimBeingDeleted(PartnerBookmarksShim* shim) {
partner_bookmarks_shim_ = NULL;
}
+void BookmarksHandler::OnManagedBookmarksChanged() {
+ BookmarkModelChanged();
+}
+
void BookmarksHandler::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
extensive_changes_ = true;
}
@@ -385,14 +366,8 @@ void BookmarksHandler::HandleCreateHomeScreenBookmarkShortcut(
if (!profile)
return;
- int64 id;
- bool is_partner;
- if (!ParseNtpBookmarkId(args, &id, &is_partner))
- return;
-
DCHECK(partner_bookmarks_shim_ != NULL);
- const BookmarkNode* node =
- partner_bookmarks_shim_->GetNodeByID(id, is_partner);
+ const BookmarkNode* node = GetNodeByID(args);
if (!node)
return;
@@ -430,3 +405,59 @@ void BookmarksHandler::OnShortcutFaviconDataAvailable(
SkColorGetG(color), SkColorGetB(color));
}
}
+
+const BookmarkNode* BookmarksHandler::GetNodeByID(
+ const base::ListValue* args) const {
+ // Parses a bookmark ID passed back from the NTP. The IDs differ from the
+ // normal int64 bookmark ID because we prepend a "p" if the ID represents a
+ // partner bookmark, and an "m" if the ID represents a managed bookmark.
+
+ if (!args || args->empty())
+ return NULL;
+
+ std::string string_id;
+ if (!args->GetString(0, &string_id) || string_id.empty()) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ bool is_partner = string_id[0] == 'p';
+ bool is_managed = string_id[0] == 'm';
+
+ if (is_partner || is_managed)
+ string_id = string_id.substr(1);
+
+ int64 id = 0;
+ if (!base::StringToInt64(string_id, &id)) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ if (is_managed)
+ return managed_bookmarks_shim_->GetNodeByID(id);
+ else
+ return partner_bookmarks_shim_->GetNodeByID(id, is_partner);
+}
+
+const BookmarkNode* BookmarksHandler::GetParentOf(
+ const BookmarkNode* node) const {
+ if (node == managed_bookmarks_shim_->GetManagedBookmarksRoot())
+ return bookmark_model_->mobile_node();
+ return partner_bookmarks_shim_->GetParentOf(node);
+}
+
+bool BookmarksHandler::IsEditable(const BookmarkNode* node) const {
+ // Reserved system nodes, partner bookmarks and managed bookmarks are not
+ // editable. Additionally, bookmark editing may be completely disabled via
+ // a managed preference.
+ const PrefService* pref = Profile::FromBrowserContext(
+ web_ui()->GetWebContents()->GetBrowserContext())->GetPrefs();
+ return partner_bookmarks_shim_->IsBookmarkEditable(node) &&
+ !managed_bookmarks_shim_->IsManagedBookmark(node) &&
+ pref->GetBoolean(prefs::kEditBookmarksEnabled);
+}
+
+bool BookmarksHandler::IsRoot(const BookmarkNode* node) const {
+ return partner_bookmarks_shim_->IsRootNode(node) &&
+ node != managed_bookmarks_shim_->GetManagedBookmarksRoot();
+}
diff --git a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h
index d834a15..9c91417 100644
--- a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h
+++ b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h
@@ -5,9 +5,11 @@
#ifndef CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_BOOKMARKS_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_BOOKMARKS_HANDLER_H_
+#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.h"
#include "chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h"
#include "chrome/common/cancelable_task_tracker.h"
#include "content/public/browser/web_ui_message_handler.h"
@@ -17,7 +19,7 @@
// In Javascript if getBookmarks() is called without any parameter, the 'Other
// Bookmark' folder and bookmark bar's bookmarks and folders are returned.
// If getBookmarks() is called with a valid bookmark folder id, the given
-// folder's bookmarks and sub folders of are returned.
+// folder's bookmarks and sub folders of it are returned.
//
// All bookmarks and subfolder is returned by bookmarks() javascript callback
// function.
@@ -46,7 +48,8 @@
// }
class BookmarksHandler : public content::WebUIMessageHandler,
public BaseBookmarkModelObserver,
- public PartnerBookmarksShim::Observer {
+ public PartnerBookmarksShim::Observer,
+ public ManagedBookmarksShim::Observer {
public:
BookmarksHandler();
virtual ~BookmarksHandler();
@@ -87,6 +90,9 @@ class BookmarksHandler : public content::WebUIMessageHandler,
virtual void PartnerShimLoaded(PartnerBookmarksShim* shim) OVERRIDE;
virtual void ShimBeingDeleted(PartnerBookmarksShim* shim) OVERRIDE;
+ // Override the methods of ManagedBookmarksShim::Observer
+ virtual void OnManagedBookmarksChanged() OVERRIDE;
+
private:
// The bookmark model being observed (if it has been attached).
BookmarkModel* bookmark_model_;
@@ -94,6 +100,9 @@ class BookmarksHandler : public content::WebUIMessageHandler,
// Information about the Partner bookmarks (must check for IsLoaded())
PartnerBookmarksShim* partner_bookmarks_shim_;
+ // Contains the bookmarks managed via enterprise policy.
+ scoped_ptr<ManagedBookmarksShim> managed_bookmarks_shim_;
+
// Whether the bookmark data has been requested by the UI yet.
bool bookmark_data_requested_;
@@ -121,7 +130,7 @@ class BookmarksHandler : public content::WebUIMessageHandler,
DictionaryValue* result);
// Sends all bookmarks and sub folders in the given folder back to the NTP.
- void QueryBookmarkFolder(const int64& id, bool is_partner_bookmark);
+ void QueryBookmarkFolder(const BookmarkNode* node);
// Sends bookmark bar's bookmarks and sub folders and other folders back to
// NTP.
@@ -136,6 +145,20 @@ class BookmarksHandler : public content::WebUIMessageHandler,
const BookmarkNode* node,
const chrome::FaviconBitmapResult& bitmap_result);
+ // Looks at an optional bookmark ID in |args| and returns the corresponding
+ // node if found, otherwise returns NULL.
+ const BookmarkNode* GetNodeByID(const base::ListValue* args) const;
+
+ // Returns the parent of |node|, or NULL if it's the root node.
+ const BookmarkNode* GetParentOf(const BookmarkNode* node) const;
+
+ // Returns true if |node| can be modified by the user.
+ bool IsEditable(const BookmarkNode* node) const;
+
+ // Returns true if |node| is the real root node (not the root node of the
+ // partner bookmarks shim nor the managed bookmark shim root).
+ bool IsRoot(const BookmarkNode* node) const;
+
DISALLOW_COPY_AND_ASSIGN(BookmarksHandler);
};
diff --git a/chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.cc b/chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.cc
new file mode 100644
index 0000000..c1f8f27
--- /dev/null
+++ b/chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/policy/configuration_policy_handler_android.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using policy::ManagedBookmarksPolicyHandler;
+
+ManagedBookmarksShim::ManagedBookmarksShim(PrefService* prefs)
+ : prefs_(prefs) {
+ registrar_.Init(prefs_);
+ registrar_.Add(
+ prefs::kManagedBookmarks,
+ base::Bind(&ManagedBookmarksShim::Reload, base::Unretained(this)));
+ Reload();
+}
+
+ManagedBookmarksShim::~ManagedBookmarksShim() {}
+
+void ManagedBookmarksShim::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ManagedBookmarksShim::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool ManagedBookmarksShim::HasManagedBookmarks() const {
+ return !root_->empty();
+}
+
+bool ManagedBookmarksShim::IsManagedBookmark(const BookmarkNode* node) const {
+ while (node != NULL) {
+ if (node == root_.get())
+ return true;
+ node = node->parent();
+ }
+ return false;
+}
+
+const BookmarkNode* ManagedBookmarksShim::GetManagedBookmarksRoot() const {
+ return root_.get();
+}
+
+const BookmarkNode* ManagedBookmarksShim::GetNodeByID(int64 id) const {
+ if (root_->id() == id)
+ return root_.get();
+ for (int i = 0; i < root_->child_count(); ++i) {
+ const BookmarkNode* child = root_->GetChild(i);
+ if (child->id() == id)
+ return child;
+ }
+ return NULL;
+}
+
+void ManagedBookmarksShim::Reload() {
+ root_.reset(new BookmarkPermanentNode(0));
+ root_->SetTitle(l10n_util::GetStringUTF16(IDS_POLICY_MANAGED_BOOKMARKS));
+
+ const base::ListValue* list = prefs_->GetList(prefs::kManagedBookmarks);
+ int64 id = 1;
+ if (list) {
+ for (base::ListValue::const_iterator it = list->begin();
+ it != list->end(); ++it) {
+ const base::DictionaryValue* dict = NULL;
+ if (!*it || !(*it)->GetAsDictionary(&dict)) {
+ NOTREACHED();
+ continue;
+ }
+
+ string16 name;
+ std::string url;
+ if (!dict->GetString(ManagedBookmarksPolicyHandler::kName, &name) ||
+ !dict->GetString(ManagedBookmarksPolicyHandler::kUrl, &url)) {
+ NOTREACHED();
+ continue;
+ }
+
+ BookmarkNode* node = new BookmarkNode(id++, GURL(url));
+ node->set_type(BookmarkNode::URL);
+ node->SetTitle(name);
+ root_->Add(node, root_->child_count());
+ }
+ }
+
+ FOR_EACH_OBSERVER(Observer, observers_, OnManagedBookmarksChanged());
+}
diff --git a/chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.h b/chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.h
new file mode 100644
index 0000000..affb1ce
--- /dev/null
+++ b/chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_MANAGED_BOOKMARKS_SHIM_H_
+#define CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_MANAGED_BOOKMARKS_SHIM_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/prefs/pref_change_registrar.h"
+
+class BookmarkNode;
+class PrefService;
+
+// A shim that lives on top of a BookmarkModel that allows the injection of
+// policy managed bookmarks without submitting changes to the user configured
+// bookmark model.
+// Policy managed bookmarks live on a subfolder of the Mobile bookmarks called
+// "Managed bookmarks" that isn't editable by the user.
+class ManagedBookmarksShim {
+ public:
+ class Observer {
+ public:
+ virtual ~Observer() {}
+ virtual void OnManagedBookmarksChanged() = 0;
+ };
+
+ // Will read managed bookmarks from the given PrefService. The preference
+ // that contains the bookmarks is managed by policy, and is updated when the
+ // policy changes.
+ explicit ManagedBookmarksShim(PrefService* prefs);
+ ~ManagedBookmarksShim();
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Returns true if there exists at least one managed bookmark.
+ bool HasManagedBookmarks() const;
+ bool IsManagedBookmark(const BookmarkNode* node) const;
+ const BookmarkNode* GetManagedBookmarksRoot() const;
+ const BookmarkNode* GetNodeByID(int64 id) const;
+ const BookmarkNode* GetParentOf(const BookmarkNode* node) const;
+
+ private:
+ void Reload();
+
+ PrefService* prefs_;
+ PrefChangeRegistrar registrar_;
+ scoped_ptr<BookmarkNode> root_;
+ ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ManagedBookmarksShim);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_MANAGED_BOOKMARKS_SHIM_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index d97c485..7dcb4cb 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1378,6 +1378,8 @@
'browser/policy/config_dir_policy_loader.h',
'browser/policy/configuration_policy_handler.cc',
'browser/policy/configuration_policy_handler.h',
+ 'browser/policy/configuration_policy_handler_android.cc',
+ 'browser/policy/configuration_policy_handler_android.h',
'browser/policy/configuration_policy_handler_list.cc',
'browser/policy/configuration_policy_handler_list.h',
'browser/policy/configuration_policy_pref_store.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index d714e22..0c2c67d 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -2770,6 +2770,8 @@
'browser/ui/webui/ntp/android/bookmarks_handler.h',
'browser/ui/webui/ntp/android/context_menu_handler.cc',
'browser/ui/webui/ntp/android/context_menu_handler.h',
+ 'browser/ui/webui/ntp/android/managed_bookmarks_shim.cc',
+ 'browser/ui/webui/ntp/android/managed_bookmarks_shim.h',
'browser/ui/webui/ntp/android/navigation_handler.cc',
'browser/ui/webui/ntp/android/navigation_handler.h',
'browser/ui/webui/ntp/android/new_tab_page_ready_handler.cc',
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 32e596d..27d9d89 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -497,6 +497,11 @@ const char kUrlWhitelist[] = "policy.url_whitelist";
// recorded on Android so that retries aren't attempted on every startup.
// Instead the cloud policy registration is retried at least 1 or 3 days later.
const char kLastPolicyCheckTime[] = "policy.last_policy_check_time";
+
+// A list of bookmarks to include in a Managed Bookmarks root node. Each
+// list item is a dictionary containig a "name" and an "url" entry, detailing
+// the bookmark name and target URL respectively.
+const char kManagedBookmarks[] = "policy.managed_bookmarks";
#endif
// Prefix URL for the experimental Instant ZeroSuggest provider.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 494e806..a9c11ee 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -193,6 +193,7 @@ extern const char kUrlBlacklist[];
extern const char kUrlWhitelist[];
#if defined(OS_ANDROID)
extern const char kLastPolicyCheckTime[];
+extern const char kManagedBookmarks[];
#endif
extern const char kInstantUIZeroSuggestUrlPrefix[];
extern const char kMultipleProfilePrefMigration[];
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 951d833..2c334c0 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1833,6 +1833,9 @@
"ContentPackManualBehaviorURLs": {
},
+ "ManagedBookmarks": {
+ },
+
"----- Chrome OS device policies ---------------------------------------": {},
"DevicePolicyRefreshRate": {
diff --git a/chrome/tools/build/generate_policy_source.py b/chrome/tools/build/generate_policy_source.py
index 3ad6d57..efe0d2f438 100755
--- a/chrome/tools/build/generate_policy_source.py
+++ b/chrome/tools/build/generate_policy_source.py
@@ -28,6 +28,8 @@ class PolicyDetails:
# - the equivalent base::Value::Type
# - the equivalent Protobuf field type
# - the name of one of the protobufs for shared policy types
+ # TODO(joaodasilva): refactor the 'dict' type into a more generic 'json' type
+ # that can also be used to represent lists of other JSON objects.
TYPE_MAP = {
'dict': ('TYPE_DICTIONARY', 'string', 'String'),
'int': ('TYPE_INTEGER', 'int64', 'Integer'),
@@ -448,18 +450,16 @@ base::ListValue* DecodeStringList(const em::StringList& string_list) {
return list_value;
}
-base::DictionaryValue* DecodeDictionaryValue(const std::string& json) {
+base::Value* DecodeJson(const std::string& json) {
scoped_ptr<base::Value> root(
base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS));
- base::DictionaryValue* dict = NULL;
- if (!root || !root->GetAsDictionary(&dict) || !dict) {
+
+ if (!root)
LOG(WARNING) << "Invalid JSON string, ignoring: " << json;
- // TODO(bartfab): Figure out a way to show errors in chrome://policy.
- return new base::DictionaryValue;
- }
- ignore_result(root.release());
- return dict;
+ // Accept any Value type that parsed as JSON, and leave it to the handler to
+ // convert and check the concrete type.
+ return root.release();
}
void DecodePolicy(const em::CloudPolicySettings& policy, PolicyMap* map) {
@@ -482,7 +482,7 @@ def _CreateValue(type, arg):
elif type == 'TYPE_LIST':
return 'DecodeStringList(%s)' % arg
elif type == 'TYPE_DICTIONARY':
- return 'DecodeDictionaryValue(%s)' % arg
+ return 'DecodeJson(%s)' % arg
else:
raise NotImplementedError('Unknown type %s' % type)