blob: 0737eff10b648eb809ba4c413213bb6bc21b7ca9 [file] [log] [blame]
// Copyright (c) 2012 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/chromeos/drive/drive_webapps_registry.h"
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_path.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/google_apis/drive_api_parser.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace drive {
namespace {
// WebApp store URL prefix.
const char kStoreProductUrl[] = "https://chrome.google.com/webstore/";
// Extracts Web store id from its web store URL.
std::string GetWebStoreIdFromUrl(const GURL& url) {
if (!StartsWithASCII(url.spec(), kStoreProductUrl, false)) {
LOG(WARNING) << "Unrecognized product URL " << url.spec();
return std::string();
}
base::FilePath path(url.path());
std::vector<base::FilePath::StringType> components;
path.GetComponents(&components);
DCHECK_LE(2U, components.size()); // Coming from kStoreProductUrl
// Return the last part of the path
return components[components.size() - 1];
}
// TODO(kochi): This is duplicate from gdata_wapi_parser.cc.
bool SortBySize(const google_apis::InstalledApp::IconList::value_type& a,
const google_apis::InstalledApp::IconList::value_type& b) {
return a.first < b.first;
}
} // namespace
// DriveWebAppInfo struct implementation.
DriveWebAppInfo::DriveWebAppInfo(
const std::string& app_id,
const google_apis::InstalledApp::IconList& app_icons,
const google_apis::InstalledApp::IconList& document_icons,
const std::string& web_store_id,
const string16& app_name,
const string16& object_type,
bool is_primary_selector)
: app_id(app_id),
app_icons(app_icons),
document_icons(document_icons),
web_store_id(web_store_id),
app_name(app_name),
object_type(object_type),
is_primary_selector(is_primary_selector) {
}
DriveWebAppInfo::~DriveWebAppInfo() {
}
// DriveFileSystem::WebAppFileSelector struct implementation.
DriveWebAppsRegistry::WebAppFileSelector::WebAppFileSelector(
const GURL& product_link,
const google_apis::InstalledApp::IconList& app_icons,
const google_apis::InstalledApp::IconList& document_icons,
const string16& object_type,
const std::string& app_id,
bool is_primary_selector)
: product_link(product_link),
app_icons(app_icons),
document_icons(document_icons),
object_type(object_type),
app_id(app_id),
is_primary_selector(is_primary_selector) {
}
DriveWebAppsRegistry::WebAppFileSelector::~WebAppFileSelector() {
}
// DriveWebAppsRegistry implementation.
DriveWebAppsRegistry::DriveWebAppsRegistry() {
}
DriveWebAppsRegistry::~DriveWebAppsRegistry() {
STLDeleteValues(&webapp_extension_map_);
STLDeleteValues(&webapp_mimetypes_map_);
}
void DriveWebAppsRegistry::GetWebAppsForFile(
const base::FilePath& file,
const std::string& mime_type,
ScopedVector<DriveWebAppInfo>* apps) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
SelectorWebAppList result_map;
if (!file.empty()) {
base::FilePath::StringType extension = file.Extension();
if (extension.size() < 2)
return;
extension = extension.substr(1);
if (!extension.empty())
FindWebAppsForSelector(extension, webapp_extension_map_, &result_map);
}
if (!mime_type.empty())
FindWebAppsForSelector(mime_type, webapp_mimetypes_map_, &result_map);
// Insert found web apps into |apps|, but skip duplicate results.
std::set<std::string> inserted_app_ids;
for (SelectorWebAppList::const_iterator it = result_map.begin();
it != result_map.end(); ++it) {
if (inserted_app_ids.find(it->second->app_id) == inserted_app_ids.end()) {
inserted_app_ids.insert(it->second->app_id);
apps->push_back(it->second);
}
}
}
std::set<std::string> DriveWebAppsRegistry::GetExtensionsForWebStoreApp(
const std::string& web_store_id) {
std::set<std::string> extensions;
// Iterate over all the registered filename extensions, looking for the given
// web_store_id.
for (WebAppFileSelectorMap::iterator iter = webapp_extension_map_.begin();
iter != webapp_extension_map_.end(); ++iter) {
std::string id = GetWebStoreIdFromUrl(iter->second->product_link);
if (id == web_store_id)
extensions.insert(iter->first);
}
return extensions;
}
void DriveWebAppsRegistry::UpdateFromFeed(
const google_apis::AccountMetadataFeed& metadata) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
url_to_name_map_.clear();
STLDeleteValues(&webapp_extension_map_);
STLDeleteValues(&webapp_mimetypes_map_);
for (ScopedVector<google_apis::InstalledApp>::const_iterator it =
metadata.installed_apps().begin();
it != metadata.installed_apps().end(); ++it) {
const google_apis::InstalledApp& app = **it;
GURL product_url = app.GetProductUrl();
if (product_url.is_empty())
continue;
google_apis::InstalledApp::IconList app_icons =
app.GetIconsForCategory(google_apis::AppIcon::ICON_APPLICATION);
google_apis::InstalledApp::IconList document_icons =
app.GetIconsForCategory(google_apis::AppIcon::ICON_DOCUMENT);
if (VLOG_IS_ON(1)) {
std::vector<std::string> mime_types;
for (size_t i = 0; i < app.primary_mimetypes().size(); ++i)
mime_types.push_back(*app.primary_mimetypes()[i]);
for (size_t i = 0; i < app.secondary_mimetypes().size(); ++i)
mime_types.push_back(*app.secondary_mimetypes()[i]);
std::vector<std::string> extensions;
for (size_t i = 0; i < app.primary_extensions().size(); ++i)
extensions.push_back(*app.primary_extensions()[i]);
for (size_t i = 0; i < app.secondary_extensions().size(); ++i)
extensions.push_back(*app.secondary_extensions()[i]);
VLOG(1) << "Adding app " << app.app_name()
<< " to app registry. mime_types: "
<< JoinString(mime_types, ',') << " extensions: "
<< JoinString(extensions, ',');
}
url_to_name_map_.insert(
std::make_pair(product_url, app.app_name()));
AddAppSelectorList(product_url,
app_icons,
document_icons,
app.object_type(),
app.app_id(),
true, // primary
app.primary_mimetypes(),
&webapp_mimetypes_map_);
AddAppSelectorList(product_url,
app_icons,
document_icons,
app.object_type(),
app.app_id(),
false, // primary
app.secondary_mimetypes(),
&webapp_mimetypes_map_);
AddAppSelectorList(product_url,
app_icons,
document_icons,
app.object_type(),
app.app_id(),
true, // primary
app.primary_extensions(),
&webapp_extension_map_);
AddAppSelectorList(product_url,
app_icons,
document_icons,
app.object_type(),
app.app_id(),
false, // primary
app.secondary_extensions(),
&webapp_extension_map_);
}
}
void DriveWebAppsRegistry::UpdateFromAppList(
const google_apis::AppList& applist) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
url_to_name_map_.clear();
STLDeleteValues(&webapp_extension_map_);
STLDeleteValues(&webapp_mimetypes_map_);
for (size_t i = 0; i < applist.items().size(); ++i) {
const google_apis::AppResource& app = *applist.items()[i];
if (app.product_url().is_empty())
continue;
google_apis::InstalledApp::IconList app_icons;
google_apis::InstalledApp::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()));
}
std::sort(app_icons.begin(), app_icons.end(), SortBySize);
std::sort(document_icons.begin(), document_icons.end(), SortBySize);
url_to_name_map_.insert(
std::make_pair(app.product_url(), app.name()));
AddAppSelectorList(app.product_url(),
app_icons,
document_icons,
app.object_type(),
app.application_id(),
true, // primary
app.primary_mimetypes(),
&webapp_mimetypes_map_);
AddAppSelectorList(app.product_url(),
app_icons,
document_icons,
app.object_type(),
app.application_id(),
false, // primary
app.secondary_mimetypes(),
&webapp_mimetypes_map_);
AddAppSelectorList(app.product_url(),
app_icons,
document_icons,
app.object_type(),
app.application_id(),
true, // primary
app.primary_file_extensions(),
&webapp_extension_map_);
AddAppSelectorList(app.product_url(),
app_icons,
document_icons,
app.object_type(),
app.application_id(),
false, // primary
app.secondary_file_extensions(),
&webapp_extension_map_);
}
}
// static.
void DriveWebAppsRegistry::AddAppSelectorList(
const GURL& product_link,
const google_apis::InstalledApp::IconList& app_icons,
const google_apis::InstalledApp::IconList& document_icons,
const std::string& object_type,
const std::string& app_id,
bool is_primary_selector,
const ScopedVector<std::string>& selectors,
WebAppFileSelectorMap* map) {
for (ScopedVector<std::string>::const_iterator it = selectors.begin();
it != selectors.end(); ++it) {
std::string* value = *it;
map->insert(std::make_pair(
*value, new WebAppFileSelector(product_link,
app_icons,
document_icons,
UTF8ToUTF16(object_type),
app_id,
is_primary_selector)));
}
}
void DriveWebAppsRegistry::FindWebAppsForSelector(
const std::string& file_selector,
const WebAppFileSelectorMap& map,
SelectorWebAppList* apps) {
for (WebAppFileSelectorMap::const_iterator it = map.find(file_selector);
it != map.end() && it->first == file_selector; ++it) {
const WebAppFileSelector* web_app = it->second;
std::map<GURL, std::string>::const_iterator product_iter =
url_to_name_map_.find(web_app->product_link);
if (product_iter == url_to_name_map_.end()) {
NOTREACHED();
continue;
}
std::string web_store_id = GetWebStoreIdFromUrl(web_app->product_link);
if (web_store_id.empty())
continue;
if (apps->find(web_app) != apps->end())
continue;
apps->insert(std::make_pair(
web_app,
new DriveWebAppInfo(web_app->app_id,
web_app->app_icons,
web_app->document_icons,
web_store_id,
UTF8ToUTF16(product_iter->second), // app name.
web_app->object_type,
web_app->is_primary_selector)));
}
}
} // namespace drive