• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/browser/chromeos/drive/file_system_util.h"
15 #include "chrome/browser/chromeos/drive/job_scheduler.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "google_apis/drive/drive_api_parser.h"
18 
19 using content::BrowserThread;
20 
21 namespace drive {
22 
23 namespace {
24 
25 // Webstore URL prefix.
26 const char kStoreProductUrl[] = "https://chrome.google.com/webstore/";
27 
28 // Extracts Web store id from its web store URL.
GetWebStoreIdFromUrl(const GURL & url)29 std::string GetWebStoreIdFromUrl(const GURL& url) {
30   if (!StartsWithASCII(url.spec(), kStoreProductUrl, false)) {
31     LOG(WARNING) << "Unrecognized product URL " << url.spec();
32     return std::string();
33   }
34 
35   base::FilePath path(url.path());
36   std::vector<base::FilePath::StringType> components;
37   path.GetComponents(&components);
38   DCHECK_LE(2U, components.size());  // Coming from kStoreProductUrl
39 
40   // Return the last part of the path
41   return components[components.size() - 1];
42 }
43 
44 }  // namespace
45 
DriveAppInfo()46 DriveAppInfo::DriveAppInfo() {
47 }
48 
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)49 DriveAppInfo::DriveAppInfo(
50     const std::string& app_id,
51     const google_apis::InstalledApp::IconList& app_icons,
52     const google_apis::InstalledApp::IconList& document_icons,
53     const std::string& web_store_id,
54     const std::string& app_name,
55     const std::string& object_type,
56     bool is_primary_selector)
57     : app_id(app_id),
58       app_icons(app_icons),
59       document_icons(document_icons),
60       web_store_id(web_store_id),
61       app_name(app_name),
62       object_type(object_type),
63       is_primary_selector(is_primary_selector) {
64 }
65 
~DriveAppInfo()66 DriveAppInfo::~DriveAppInfo() {
67 }
68 
DriveAppRegistry(JobScheduler * scheduler)69 DriveAppRegistry::DriveAppRegistry(JobScheduler* scheduler)
70     : scheduler_(scheduler),
71       is_updating_(false),
72       weak_ptr_factory_(this) {
73 }
74 
~DriveAppRegistry()75 DriveAppRegistry::~DriveAppRegistry() {
76   STLDeleteValues(&app_extension_map_);
77   STLDeleteValues(&app_mimetypes_map_);
78 }
79 
GetAppsForFile(const base::FilePath::StringType & file_extension,const std::string & mime_type,ScopedVector<DriveAppInfo> * apps) const80 void DriveAppRegistry::GetAppsForFile(
81     const base::FilePath::StringType& file_extension,
82     const std::string& mime_type,
83     ScopedVector<DriveAppInfo>* apps) const {
84   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
85 
86   std::vector<DriveAppInfo*> matched_apps;
87   if (!file_extension.empty()) {
88     const base::FilePath::StringType without_dot = file_extension.substr(1);
89     FindAppsForSelector(without_dot, app_extension_map_, &matched_apps);
90   }
91   if (!mime_type.empty())
92     FindAppsForSelector(mime_type, app_mimetypes_map_, &matched_apps);
93 
94   // Insert found Drive apps into |apps|, but skip duplicate results.
95   std::set<std::string> inserted_app_ids;
96   for (size_t i = 0; i < matched_apps.size(); ++i) {
97     if (inserted_app_ids.count(matched_apps[i]->app_id) == 0) {
98       inserted_app_ids.insert(matched_apps[i]->app_id);
99       apps->push_back(new DriveAppInfo(*matched_apps[i]));
100     }
101   }
102 }
103 
Update()104 void DriveAppRegistry::Update() {
105   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
106 
107   if (is_updating_)  // There is already an update in progress.
108     return;
109 
110   is_updating_ = true;
111 
112   scheduler_->GetAppList(
113       base::Bind(&DriveAppRegistry::UpdateAfterGetAppList,
114                  weak_ptr_factory_.GetWeakPtr()));
115 }
116 
UpdateAfterGetAppList(google_apis::GDataErrorCode gdata_error,scoped_ptr<google_apis::AppList> app_list)117 void DriveAppRegistry::UpdateAfterGetAppList(
118     google_apis::GDataErrorCode gdata_error,
119     scoped_ptr<google_apis::AppList> app_list) {
120   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
121 
122   DCHECK(is_updating_);
123   is_updating_ = false;
124 
125   FileError error = GDataToFileError(gdata_error);
126   if (error != FILE_ERROR_OK) {
127     // Failed to fetch the data from the server. We can do nothing here.
128     return;
129   }
130 
131   DCHECK(app_list);
132   UpdateFromAppList(*app_list);
133 }
134 
UpdateFromAppList(const google_apis::AppList & app_list)135 void DriveAppRegistry::UpdateFromAppList(
136     const google_apis::AppList& app_list) {
137   STLDeleteValues(&app_extension_map_);
138   STLDeleteValues(&app_mimetypes_map_);
139 
140   for (size_t i = 0; i < app_list.items().size(); ++i) {
141     const google_apis::AppResource& app = *app_list.items()[i];
142 
143     if (app.product_url().is_empty())
144       continue;
145     std::string web_store_id = GetWebStoreIdFromUrl(app.product_url());
146     if (web_store_id.empty())
147       continue;
148 
149     google_apis::InstalledApp::IconList app_icons;
150     google_apis::InstalledApp::IconList document_icons;
151     for (size_t j = 0; j < app.icons().size(); ++j) {
152       const google_apis::DriveAppIcon& icon = *app.icons()[j];
153       if (icon.icon_url().is_empty())
154         continue;
155       if (icon.category() == google_apis::DriveAppIcon::APPLICATION)
156         app_icons.push_back(std::make_pair(icon.icon_side_length(),
157                                            icon.icon_url()));
158       if (icon.category() == google_apis::DriveAppIcon::DOCUMENT)
159         document_icons.push_back(std::make_pair(icon.icon_side_length(),
160                                                 icon.icon_url()));
161     }
162 
163     AddAppSelectorList(web_store_id,
164                        app.name(),
165                        app_icons,
166                        document_icons,
167                        app.object_type(),
168                        app.application_id(),
169                        true,   // primary
170                        app.primary_mimetypes(),
171                        &app_mimetypes_map_);
172     AddAppSelectorList(web_store_id,
173                        app.name(),
174                        app_icons,
175                        document_icons,
176                        app.object_type(),
177                        app.application_id(),
178                        false,   // primary
179                        app.secondary_mimetypes(),
180                        &app_mimetypes_map_);
181     AddAppSelectorList(web_store_id,
182                        app.name(),
183                        app_icons,
184                        document_icons,
185                        app.object_type(),
186                        app.application_id(),
187                        true,   // primary
188                        app.primary_file_extensions(),
189                        &app_extension_map_);
190     AddAppSelectorList(web_store_id,
191                        app.name(),
192                        app_icons,
193                        document_icons,
194                        app.object_type(),
195                        app.application_id(),
196                        false,   // primary
197                        app.secondary_file_extensions(),
198                        &app_extension_map_);
199   }
200 }
201 
202 // static.
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)203 void DriveAppRegistry::AddAppSelectorList(
204     const std::string& web_store_id,
205     const std::string& app_name,
206     const google_apis::InstalledApp::IconList& app_icons,
207     const google_apis::InstalledApp::IconList& document_icons,
208     const std::string& object_type,
209     const std::string& app_id,
210     bool is_primary_selector,
211     const ScopedVector<std::string>& selectors,
212     DriveAppFileSelectorMap* map) {
213   for (ScopedVector<std::string>::const_iterator it = selectors.begin();
214        it != selectors.end(); ++it) {
215     std::string* value = *it;
216     map->insert(std::make_pair(
217         *value, new DriveAppInfo(app_id,
218                                  app_icons,
219                                  document_icons,
220                                  web_store_id,
221                                  app_name,
222                                  object_type,
223                                  is_primary_selector)));
224   }
225 }
226 
FindAppsForSelector(const std::string & file_selector,const DriveAppFileSelectorMap & map,std::vector<DriveAppInfo * > * matched_apps) const227 void DriveAppRegistry::FindAppsForSelector(
228     const std::string& file_selector,
229     const DriveAppFileSelectorMap& map,
230     std::vector<DriveAppInfo*>* matched_apps) const {
231   for (DriveAppFileSelectorMap::const_iterator it = map.find(file_selector);
232        it != map.end() && it->first == file_selector; ++it) {
233     matched_apps->push_back(it->second);
234   }
235 }
236 
237 namespace util {
238 
FindPreferredIcon(const google_apis::InstalledApp::IconList & icons,int preferred_size)239 GURL FindPreferredIcon(
240     const google_apis::InstalledApp::IconList& icons,
241     int preferred_size) {
242   if (icons.empty())
243     return GURL();
244 
245   google_apis::InstalledApp::IconList sorted_icons = icons;
246   std::sort(sorted_icons.begin(), sorted_icons.end());
247   GURL result = sorted_icons.rbegin()->second;
248   for (google_apis::InstalledApp::IconList::const_reverse_iterator
249            iter = sorted_icons.rbegin();
250        iter != sorted_icons.rend() && iter->first >= preferred_size; ++iter) {
251     result = iter->second;
252   }
253   return result;
254 }
255 
256 }  // namespace util
257 }  // namespace drive
258