blob: 629a2d975eeb712549e28c5c87a86c7d3fc3232b [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_app_registry.h"
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_path.h"
#include "base/strings/string_util.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/job_scheduler.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/drive/drive_api_parser.h"
using content::BrowserThread;
namespace drive {
namespace {
// Webstore 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];
}
} // namespace
DriveAppInfo::DriveAppInfo() {
}
DriveAppInfo::DriveAppInfo(
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 std::string& app_name,
const std::string& 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) {
}
DriveAppInfo::~DriveAppInfo() {
}
DriveAppRegistry::DriveAppRegistry(JobScheduler* scheduler)
: scheduler_(scheduler),
is_updating_(false),
weak_ptr_factory_(this) {
}
DriveAppRegistry::~DriveAppRegistry() {
STLDeleteValues(&app_extension_map_);
STLDeleteValues(&app_mimetypes_map_);
}
void DriveAppRegistry::GetAppsForFile(
const base::FilePath::StringType& file_extension,
const std::string& mime_type,
ScopedVector<DriveAppInfo>* apps) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
std::vector<DriveAppInfo*> matched_apps;
if (!file_extension.empty()) {
const base::FilePath::StringType without_dot = file_extension.substr(1);
FindAppsForSelector(without_dot, app_extension_map_, &matched_apps);
}
if (!mime_type.empty())
FindAppsForSelector(mime_type, app_mimetypes_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]->app_id) == 0) {
inserted_app_ids.insert(matched_apps[i]->app_id);
apps->push_back(new DriveAppInfo(*matched_apps[i]));
}
}
}
void DriveAppRegistry::Update() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (is_updating_) // There is already an update in progress.
return;
is_updating_ = true;
scheduler_->GetAppList(
base::Bind(&DriveAppRegistry::UpdateAfterGetAppList,
weak_ptr_factory_.GetWeakPtr()));
}
void DriveAppRegistry::UpdateAfterGetAppList(
google_apis::GDataErrorCode gdata_error,
scoped_ptr<google_apis::AppList> app_list) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(is_updating_);
is_updating_ = false;
FileError error = GDataToFileError(gdata_error);
if (error != FILE_ERROR_OK) {
// Failed to fetch the data from the server. We can do nothing here.
return;
}
DCHECK(app_list);
UpdateFromAppList(*app_list);
}
void DriveAppRegistry::UpdateFromAppList(
const google_apis::AppList& app_list) {
STLDeleteValues(&app_extension_map_);
STLDeleteValues(&app_mimetypes_map_);
for (size_t i = 0; i < app_list.items().size(); ++i) {
const google_apis::AppResource& app = *app_list.items()[i];
if (app.product_url().is_empty())
continue;
std::string web_store_id = GetWebStoreIdFromUrl(app.product_url());
if (web_store_id.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()));
}
AddAppSelectorList(web_store_id,
app.name(),
app_icons,
document_icons,
app.object_type(),
app.application_id(),
true, // primary
app.primary_mimetypes(),
&app_mimetypes_map_);
AddAppSelectorList(web_store_id,
app.name(),
app_icons,
document_icons,
app.object_type(),
app.application_id(),
false, // primary
app.secondary_mimetypes(),
&app_mimetypes_map_);
AddAppSelectorList(web_store_id,
app.name(),
app_icons,
document_icons,
app.object_type(),
app.application_id(),
true, // primary
app.primary_file_extensions(),
&app_extension_map_);
AddAppSelectorList(web_store_id,
app.name(),
app_icons,
document_icons,
app.object_type(),
app.application_id(),
false, // primary
app.secondary_file_extensions(),
&app_extension_map_);
}
}
// static.
void DriveAppRegistry::AddAppSelectorList(
const std::string& web_store_id,
const std::string& app_name,
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,
DriveAppFileSelectorMap* 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 DriveAppInfo(app_id,
app_icons,
document_icons,
web_store_id,
app_name,
object_type,
is_primary_selector)));
}
}
void DriveAppRegistry::FindAppsForSelector(
const std::string& file_selector,
const DriveAppFileSelectorMap& map,
std::vector<DriveAppInfo*>* matched_apps) const {
for (DriveAppFileSelectorMap::const_iterator it = map.find(file_selector);
it != map.end() && it->first == file_selector; ++it) {
matched_apps->push_back(it->second);
}
}
namespace util {
GURL FindPreferredIcon(
const google_apis::InstalledApp::IconList& icons,
int preferred_size) {
if (icons.empty())
return GURL();
google_apis::InstalledApp::IconList sorted_icons = icons;
std::sort(sorted_icons.begin(), sorted_icons.end());
GURL result = sorted_icons.rbegin()->second;
for (google_apis::InstalledApp::IconList::const_reverse_iterator
iter = sorted_icons.rbegin();
iter != sorted_icons.rend() && iter->first >= preferred_size; ++iter) {
result = iter->second;
}
return result;
}
} // namespace util
} // namespace drive