Home | History | Annotate | Download | only in drive
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/drive/drive_app_registry.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <utility>
     10 #include <vector>
     11 
     12 #include "base/files/file_path.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "chrome/browser/chromeos/drive/file_system_util.h"
     16 #include "chrome/browser/chromeos/drive/job_scheduler.h"
     17 #include "chrome/browser/google_apis/drive_api_parser.h"
     18 #include "content/public/browser/browser_thread.h"
     19 
     20 using content::BrowserThread;
     21 
     22 namespace drive {
     23 
     24 namespace {
     25 
     26 // Webstore URL prefix.
     27 const char kStoreProductUrl[] = "https://chrome.google.com/webstore/";
     28 
     29 // Extracts Web store id from its web store URL.
     30 std::string GetWebStoreIdFromUrl(const GURL& url) {
     31   if (!StartsWithASCII(url.spec(), kStoreProductUrl, false)) {
     32     LOG(WARNING) << "Unrecognized product URL " << url.spec();
     33     return std::string();
     34   }
     35 
     36   base::FilePath path(url.path());
     37   std::vector<base::FilePath::StringType> components;
     38   path.GetComponents(&components);
     39   DCHECK_LE(2U, components.size());  // Coming from kStoreProductUrl
     40 
     41   // Return the last part of the path
     42   return components[components.size() - 1];
     43 }
     44 
     45 bool SortBySize(const google_apis::InstalledApp::IconList::value_type& a,
     46                 const google_apis::InstalledApp::IconList::value_type& b) {
     47   return a.first < b.first;
     48 }
     49 
     50 }  // namespace
     51 
     52 // DriveAppInfo struct implementation.
     53 
     54 DriveAppInfo::DriveAppInfo(
     55     const std::string& app_id,
     56     const google_apis::InstalledApp::IconList& app_icons,
     57     const google_apis::InstalledApp::IconList& document_icons,
     58     const std::string& web_store_id,
     59     const string16& app_name,
     60     const string16& object_type,
     61     bool is_primary_selector)
     62     : app_id(app_id),
     63       app_icons(app_icons),
     64       document_icons(document_icons),
     65       web_store_id(web_store_id),
     66       app_name(app_name),
     67       object_type(object_type),
     68       is_primary_selector(is_primary_selector) {
     69 }
     70 
     71 DriveAppInfo::~DriveAppInfo() {
     72 }
     73 
     74 // FileSystem::DriveAppFileSelector struct implementation.
     75 
     76 DriveAppRegistry::DriveAppFileSelector::DriveAppFileSelector(
     77     const GURL& product_link,
     78     const google_apis::InstalledApp::IconList& app_icons,
     79     const google_apis::InstalledApp::IconList& document_icons,
     80     const string16& object_type,
     81     const std::string& app_id,
     82     bool is_primary_selector)
     83     : product_link(product_link),
     84       app_icons(app_icons),
     85       document_icons(document_icons),
     86       object_type(object_type),
     87       app_id(app_id),
     88       is_primary_selector(is_primary_selector) {
     89 }
     90 
     91 DriveAppRegistry::DriveAppFileSelector::~DriveAppFileSelector() {
     92 }
     93 
     94 // DriveAppRegistry implementation.
     95 
     96 DriveAppRegistry::DriveAppRegistry(JobScheduler* scheduler)
     97     : scheduler_(scheduler),
     98       is_updating_(false),
     99       weak_ptr_factory_(this) {
    100 }
    101 
    102 DriveAppRegistry::~DriveAppRegistry() {
    103   STLDeleteValues(&app_extension_map_);
    104   STLDeleteValues(&app_mimetypes_map_);
    105 }
    106 
    107 void DriveAppRegistry::GetAppsForFile(
    108     const base::FilePath& file_path,
    109     const std::string& mime_type,
    110     ScopedVector<DriveAppInfo>* apps) {
    111   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    112 
    113   SelectorAppList result_map;
    114   if (!file_path.empty()) {
    115     base::FilePath::StringType extension = file_path.Extension();
    116     if (extension.size() < 2)
    117       return;
    118 
    119     extension = extension.substr(1);
    120     if (!extension.empty())
    121       FindAppsForSelector(extension, app_extension_map_, &result_map);
    122   }
    123 
    124   if (!mime_type.empty())
    125     FindAppsForSelector(mime_type, app_mimetypes_map_, &result_map);
    126 
    127   // Insert found web apps into |apps|, but skip duplicate results.
    128   std::set<std::string> inserted_app_ids;
    129   for (SelectorAppList::const_iterator it = result_map.begin();
    130        it != result_map.end(); ++it) {
    131     if (inserted_app_ids.find(it->second->app_id) == inserted_app_ids.end()) {
    132       inserted_app_ids.insert(it->second->app_id);
    133       apps->push_back(it->second);
    134     }
    135   }
    136 }
    137 
    138 void DriveAppRegistry::Update() {
    139   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    140 
    141   if (is_updating_)  // There is already an update in progress.
    142     return;
    143 
    144   is_updating_ = true;
    145 
    146   scheduler_->GetAppList(
    147       base::Bind(&DriveAppRegistry::UpdateAfterGetAppList,
    148                  weak_ptr_factory_.GetWeakPtr()));
    149 }
    150 
    151 void DriveAppRegistry::UpdateAfterGetAppList(
    152     google_apis::GDataErrorCode gdata_error,
    153     scoped_ptr<google_apis::AppList> app_list) {
    154   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    155 
    156   DCHECK(is_updating_);
    157   is_updating_ = false;
    158 
    159   FileError error = GDataToFileError(gdata_error);
    160   if (error != FILE_ERROR_OK) {
    161     // Failed to fetch the data from the server. We can do nothing here.
    162     return;
    163   }
    164 
    165   DCHECK(app_list);
    166 
    167   url_to_name_map_.clear();
    168   STLDeleteValues(&app_extension_map_);
    169   STLDeleteValues(&app_mimetypes_map_);
    170   for (size_t i = 0; i < app_list->items().size(); ++i) {
    171     const google_apis::AppResource& app = *app_list->items()[i];
    172     if (app.product_url().is_empty())
    173       continue;
    174 
    175     google_apis::InstalledApp::IconList app_icons;
    176     google_apis::InstalledApp::IconList document_icons;
    177     for (size_t j = 0; j < app.icons().size(); ++j) {
    178       const google_apis::DriveAppIcon& icon = *app.icons()[j];
    179       if (icon.icon_url().is_empty())
    180         continue;
    181       if (icon.category() == google_apis::DriveAppIcon::APPLICATION)
    182         app_icons.push_back(std::make_pair(icon.icon_side_length(),
    183                                            icon.icon_url()));
    184       if (icon.category() == google_apis::DriveAppIcon::DOCUMENT)
    185         document_icons.push_back(std::make_pair(icon.icon_side_length(),
    186                                                 icon.icon_url()));
    187     }
    188     std::sort(app_icons.begin(), app_icons.end(), SortBySize);
    189     std::sort(document_icons.begin(), document_icons.end(), SortBySize);
    190 
    191     url_to_name_map_.insert(
    192         std::make_pair(app.product_url(), app.name()));
    193     AddAppSelectorList(app.product_url(),
    194                        app_icons,
    195                        document_icons,
    196                        app.object_type(),
    197                        app.application_id(),
    198                        true,   // primary
    199                        app.primary_mimetypes(),
    200                        &app_mimetypes_map_);
    201     AddAppSelectorList(app.product_url(),
    202                        app_icons,
    203                        document_icons,
    204                        app.object_type(),
    205                        app.application_id(),
    206                        false,   // primary
    207                        app.secondary_mimetypes(),
    208                        &app_mimetypes_map_);
    209     AddAppSelectorList(app.product_url(),
    210                        app_icons,
    211                        document_icons,
    212                        app.object_type(),
    213                        app.application_id(),
    214                        true,   // primary
    215                        app.primary_file_extensions(),
    216                        &app_extension_map_);
    217     AddAppSelectorList(app.product_url(),
    218                        app_icons,
    219                        document_icons,
    220                        app.object_type(),
    221                        app.application_id(),
    222                        false,   // primary
    223                        app.secondary_file_extensions(),
    224                        &app_extension_map_);
    225   }
    226 }
    227 
    228 // static.
    229 void DriveAppRegistry::AddAppSelectorList(
    230     const GURL& product_link,
    231     const google_apis::InstalledApp::IconList& app_icons,
    232     const google_apis::InstalledApp::IconList& document_icons,
    233     const std::string& object_type,
    234     const std::string& app_id,
    235     bool is_primary_selector,
    236     const ScopedVector<std::string>& selectors,
    237     DriveAppFileSelectorMap* map) {
    238   for (ScopedVector<std::string>::const_iterator it = selectors.begin();
    239        it != selectors.end(); ++it) {
    240     std::string* value = *it;
    241     map->insert(std::make_pair(
    242         *value, new DriveAppFileSelector(product_link,
    243                                          app_icons,
    244                                          document_icons,
    245                                          UTF8ToUTF16(object_type),
    246                                          app_id,
    247                                          is_primary_selector)));
    248   }
    249 }
    250 
    251 void DriveAppRegistry::FindAppsForSelector(
    252     const std::string& file_selector,
    253     const DriveAppFileSelectorMap& map,
    254     SelectorAppList* apps) {
    255   for (DriveAppFileSelectorMap::const_iterator it = map.find(file_selector);
    256        it != map.end() && it->first == file_selector; ++it) {
    257     const DriveAppFileSelector* web_app = it->second;
    258     std::map<GURL, std::string>::const_iterator product_iter =
    259         url_to_name_map_.find(web_app->product_link);
    260     if (product_iter == url_to_name_map_.end()) {
    261       NOTREACHED();
    262       continue;
    263     }
    264 
    265     std::string web_store_id = GetWebStoreIdFromUrl(web_app->product_link);
    266     if (web_store_id.empty())
    267       continue;
    268 
    269     if (apps->find(web_app) != apps->end())
    270       continue;
    271 
    272     apps->insert(std::make_pair(
    273         web_app,
    274         new DriveAppInfo(web_app->app_id,
    275                          web_app->app_icons,
    276                          web_app->document_icons,
    277                          web_store_id,
    278                          UTF8ToUTF16(product_iter->second),   // app name.
    279                          web_app->object_type,
    280                          web_app->is_primary_selector)));
    281   }
    282 }
    283 
    284 }  // namespace drive
    285