diff options
author | joaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-30 13:40:38 +0000 |
---|---|---|
committer | joaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-30 13:40:38 +0000 |
commit | 1b8acdba23bba89eb14877c3964415eb0f3b8dfb (patch) | |
tree | 140104e98f12672576b8060ae2570d92a57ac9b0 | |
parent | f3b2b8d149f79bcbc3f6f89115654e69bf7818fe (diff) | |
download | chromium_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.grd | 9 | ||||
-rw-r--r-- | chrome/app/policy/policy_templates.json | 34 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_handler_android.cc | 103 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_handler_android.h | 39 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_handler_list.cc | 8 | ||||
-rw-r--r-- | chrome/browser/policy/profile_policy_connector_factory.cc | 9 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc | 187 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/bookmarks_handler.h | 29 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.cc | 96 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/managed_bookmarks_shim.h | 56 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_browser_ui.gypi | 2 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 5 | ||||
-rw-r--r-- | chrome/common/pref_names.h | 1 | ||||
-rw-r--r-- | chrome/test/data/policy/policy_test_cases.json | 3 | ||||
-rwxr-xr-x | chrome/tools/build/generate_policy_source.py | 18 |
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) |