diff options
Diffstat (limited to 'components/drive/drive_app_registry.cc')
-rw-r--r-- | components/drive/drive_app_registry.cc | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/components/drive/drive_app_registry.cc b/components/drive/drive_app_registry.cc new file mode 100644 index 0000000..90598e7 --- /dev/null +++ b/components/drive/drive_app_registry.cc @@ -0,0 +1,246 @@ +// Copyright 2014 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 "components/drive/drive_app_registry.h" + +#include <algorithm> +#include <set> +#include <utility> + +#include "base/callback.h" +#include "base/files/file_path.h" +#include "components/drive/drive_app_registry_observer.h" +#include "components/drive/service/drive_service_interface.h" +#include "google_apis/drive/drive_api_parser.h" +#include "google_apis/google_api_keys.h" + +namespace { + +// Add {selector -> app_id} mapping to |map|. +void AddAppSelectorList(const ScopedVector<std::string>& selectors, + const std::string& app_id, + std::multimap<std::string, std::string>* map) { + for (size_t i = 0; i < selectors.size(); ++i) + map->insert(std::make_pair(*selectors[i], app_id)); +} + +// Append list of app ids in |map| looked up by |selector| to |matched_apps|. +void FindAppsForSelector(const std::string& selector, + const std::multimap<std::string, std::string>& map, + std::vector<std::string>* matched_apps) { + typedef std::multimap<std::string, std::string>::const_iterator iterator; + std::pair<iterator, iterator> range = map.equal_range(selector); + for (iterator it = range.first; it != range.second; ++it) + matched_apps->push_back(it->second); +} + +void RemoveAppFromSelector(const std::string& app_id, + std::multimap<std::string, std::string>* map) { + typedef std::multimap<std::string, std::string>::iterator iterator; + for (iterator it = map->begin(); it != map->end(); ) { + iterator now = it++; + if (now->second == app_id) + map->erase(now); + } +} + +} // namespace + +namespace drive { + +DriveAppInfo::DriveAppInfo() { +} + +DriveAppInfo::DriveAppInfo( + const std::string& app_id, + const std::string& product_id, + const IconList& app_icons, + const IconList& document_icons, + const std::string& app_name, + const GURL& create_url, + bool is_removable) + : app_id(app_id), + product_id(product_id), + app_icons(app_icons), + document_icons(document_icons), + app_name(app_name), + create_url(create_url), + is_removable(is_removable) { +} + +DriveAppInfo::~DriveAppInfo() { +} + +DriveAppRegistry::DriveAppRegistry(DriveServiceInterface* drive_service) + : drive_service_(drive_service), + is_updating_(false), + weak_ptr_factory_(this) { +} + +DriveAppRegistry::~DriveAppRegistry() { +} + +void DriveAppRegistry::GetAppsForFile( + const base::FilePath::StringType& file_extension, + const std::string& mime_type, + std::vector<DriveAppInfo>* apps) const { + DCHECK(thread_checker_.CalledOnValidThread()); + + std::vector<std::string> matched_apps; + if (!file_extension.empty()) { + const std::string without_dot = + base::FilePath(file_extension.substr(1)).AsUTF8Unsafe(); + FindAppsForSelector(without_dot, extension_map_, &matched_apps); + } + if (!mime_type.empty()) + FindAppsForSelector(mime_type, mimetype_map_, &matched_apps); + + // Insert found Drive apps into |apps|, but skip duplicate results. + std::set<std::string> inserted_app_ids; + for (size_t i = 0; i < matched_apps.size(); ++i) { + if (inserted_app_ids.count(matched_apps[i]) == 0) { + inserted_app_ids.insert(matched_apps[i]); + std::map<std::string, DriveAppInfo>::const_iterator it = + all_apps_.find(matched_apps[i]); + DCHECK(it != all_apps_.end()); + apps->push_back(it->second); + } + } +} + +void DriveAppRegistry::GetAppList(std::vector<DriveAppInfo>* apps) const { + DCHECK(thread_checker_.CalledOnValidThread()); + + apps->clear(); + for (std::map<std::string, DriveAppInfo>::const_iterator + it = all_apps_.begin(); it != all_apps_.end(); ++it) { + apps->push_back(it->second); + } +} + +void DriveAppRegistry::Update() { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (is_updating_) // There is already an update in progress. + return; + is_updating_ = true; + + drive_service_->GetAppList( + base::Bind(&DriveAppRegistry::UpdateAfterGetAppList, + weak_ptr_factory_.GetWeakPtr())); +} + +void DriveAppRegistry::UpdateAfterGetAppList( + google_apis::DriveApiErrorCode gdata_error, + scoped_ptr<google_apis::AppList> app_list) { + DCHECK(thread_checker_.CalledOnValidThread()); + + DCHECK(is_updating_); + is_updating_ = false; + + // Failed to fetch the data from the server. We can do nothing here. + if (gdata_error != google_apis::HTTP_SUCCESS) + return; + + DCHECK(app_list); + UpdateFromAppList(*app_list); +} + +void DriveAppRegistry::UpdateFromAppList(const google_apis::AppList& app_list) { + all_apps_.clear(); + extension_map_.clear(); + mimetype_map_.clear(); + + for (size_t i = 0; i < app_list.items().size(); ++i) { + const google_apis::AppResource& app = *app_list.items()[i]; + const std::string id = app.application_id(); + + DriveAppInfo::IconList app_icons; + DriveAppInfo::IconList document_icons; + for (size_t j = 0; j < app.icons().size(); ++j) { + const google_apis::DriveAppIcon& icon = *app.icons()[j]; + if (icon.icon_url().is_empty()) + continue; + if (icon.category() == google_apis::DriveAppIcon::APPLICATION) + app_icons.push_back(std::make_pair(icon.icon_side_length(), + icon.icon_url())); + if (icon.category() == google_apis::DriveAppIcon::DOCUMENT) + document_icons.push_back(std::make_pair(icon.icon_side_length(), + icon.icon_url())); + } + + all_apps_[id] = DriveAppInfo(app.application_id(), + app.product_id(), + app_icons, + document_icons, + app.name(), + app.create_url(), + app.is_removable()); + + // TODO(kinaba): consider taking primary/secondary distinction into account. + AddAppSelectorList(app.primary_mimetypes(), id, &mimetype_map_); + AddAppSelectorList(app.secondary_mimetypes(), id, &mimetype_map_); + AddAppSelectorList(app.primary_file_extensions(), id, &extension_map_); + AddAppSelectorList(app.secondary_file_extensions(), id, &extension_map_); + } + + FOR_EACH_OBSERVER(DriveAppRegistryObserver, + observers_, + OnDriveAppRegistryUpdated()); +} + +void DriveAppRegistry::AddObserver(DriveAppRegistryObserver* observer) { + observers_.AddObserver(observer); +} + +void DriveAppRegistry::RemoveObserver(DriveAppRegistryObserver* observer) { + observers_.RemoveObserver(observer); +} + +void DriveAppRegistry::UninstallApp(const std::string& app_id, + const UninstallCallback& callback) { + DCHECK(!callback.is_null()); + + drive_service_->UninstallApp(app_id, + base::Bind(&DriveAppRegistry::OnAppUninstalled, + weak_ptr_factory_.GetWeakPtr(), + app_id, + callback)); +} + +void DriveAppRegistry::OnAppUninstalled(const std::string& app_id, + const UninstallCallback& callback, + google_apis::DriveApiErrorCode error) { + if (error == google_apis::HTTP_NO_CONTENT) { + all_apps_.erase(app_id); + RemoveAppFromSelector(app_id, &mimetype_map_); + RemoveAppFromSelector(app_id, &extension_map_); + } + callback.Run(error); +} + +// static +bool DriveAppRegistry::IsAppUninstallSupported() { + return google_apis::IsGoogleChromeAPIKeyUsed(); +} + +namespace util { + +GURL FindPreferredIcon(const DriveAppInfo::IconList& icons, + int preferred_size) { + if (icons.empty()) + return GURL(); + + DriveAppInfo::IconList sorted_icons = icons; + std::sort(sorted_icons.rbegin(), sorted_icons.rend()); + + // Go forward while the size is larger or equal to preferred_size. + size_t i = 1; + while (i < sorted_icons.size() && sorted_icons[i].first >= preferred_size) + ++i; + return sorted_icons[i - 1].second; +} + +} // namespace util +} // namespace drive |