1 // Copyright 2014 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.
5 #include "chrome/browser/drive/drive_app_registry.h"
11 #include "base/callback.h"
12 #include "base/files/file_path.h"
13 #include "chrome/browser/drive/drive_service_interface.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "google_apis/drive/drive_api_parser.h"
16 #include "google_apis/google_api_keys.h"
18 using content::BrowserThread
;
22 // Add {selector -> app_id} mapping to |map|.
23 void AddAppSelectorList(const ScopedVector
<std::string
>& selectors
,
24 const std::string
& app_id
,
25 std::multimap
<std::string
, std::string
>* map
) {
26 for (size_t i
= 0; i
< selectors
.size(); ++i
)
27 map
->insert(std::make_pair(*selectors
[i
], app_id
));
30 // Append list of app ids in |map| looked up by |selector| to |matched_apps|.
31 void FindAppsForSelector(const std::string
& selector
,
32 const std::multimap
<std::string
, std::string
>& map
,
33 std::vector
<std::string
>* matched_apps
) {
34 typedef std::multimap
<std::string
, std::string
>::const_iterator iterator
;
35 std::pair
<iterator
, iterator
> range
= map
.equal_range(selector
);
36 for (iterator it
= range
.first
; it
!= range
.second
; ++it
)
37 matched_apps
->push_back(it
->second
);
40 void RemoveAppFromSelector(const std::string
& app_id
,
41 std::multimap
<std::string
, std::string
>* map
) {
42 typedef std::multimap
<std::string
, std::string
>::iterator iterator
;
43 for (iterator it
= map
->begin(); it
!= map
->end(); ) {
45 if (now
->second
== app_id
)
54 DriveAppInfo::DriveAppInfo() {
57 DriveAppInfo::DriveAppInfo(
58 const std::string
& app_id
,
59 const google_apis::InstalledApp::IconList
& app_icons
,
60 const google_apis::InstalledApp::IconList
& document_icons
,
61 const std::string
& app_name
,
62 const GURL
& create_url
)
65 document_icons(document_icons
),
67 create_url(create_url
) {
70 DriveAppInfo::~DriveAppInfo() {
73 DriveAppRegistry::DriveAppRegistry(DriveServiceInterface
* drive_service
)
74 : drive_service_(drive_service
),
76 weak_ptr_factory_(this) {
79 DriveAppRegistry::~DriveAppRegistry() {
82 void DriveAppRegistry::GetAppsForFile(
83 const base::FilePath::StringType
& file_extension
,
84 const std::string
& mime_type
,
85 std::vector
<DriveAppInfo
>* apps
) const {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
88 std::vector
<std::string
> matched_apps
;
89 if (!file_extension
.empty()) {
90 const std::string without_dot
=
91 base::FilePath(file_extension
.substr(1)).AsUTF8Unsafe();
92 FindAppsForSelector(without_dot
, extension_map_
, &matched_apps
);
94 if (!mime_type
.empty())
95 FindAppsForSelector(mime_type
, mimetype_map_
, &matched_apps
);
97 // Insert found Drive apps into |apps|, but skip duplicate results.
98 std::set
<std::string
> inserted_app_ids
;
99 for (size_t i
= 0; i
< matched_apps
.size(); ++i
) {
100 if (inserted_app_ids
.count(matched_apps
[i
]) == 0) {
101 inserted_app_ids
.insert(matched_apps
[i
]);
102 std::map
<std::string
, DriveAppInfo
>::const_iterator it
=
103 all_apps_
.find(matched_apps
[i
]);
104 DCHECK(it
!= all_apps_
.end());
105 apps
->push_back(it
->second
);
110 void DriveAppRegistry::GetAppList(std::vector
<DriveAppInfo
>* apps
) const {
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
114 for (std::map
<std::string
, DriveAppInfo
>::const_iterator
115 it
= all_apps_
.begin(); it
!= all_apps_
.end(); ++it
) {
116 apps
->push_back(it
->second
);
120 void DriveAppRegistry::Update() {
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
123 if (is_updating_
) // There is already an update in progress.
127 drive_service_
->GetAppList(
128 base::Bind(&DriveAppRegistry::UpdateAfterGetAppList
,
129 weak_ptr_factory_
.GetWeakPtr()));
132 void DriveAppRegistry::UpdateAfterGetAppList(
133 google_apis::GDataErrorCode gdata_error
,
134 scoped_ptr
<google_apis::AppList
> app_list
) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
137 DCHECK(is_updating_
);
138 is_updating_
= false;
140 // Failed to fetch the data from the server. We can do nothing here.
141 if (gdata_error
!= google_apis::HTTP_SUCCESS
)
145 UpdateFromAppList(*app_list
);
148 void DriveAppRegistry::UpdateFromAppList(const google_apis::AppList
& app_list
) {
150 extension_map_
.clear();
151 mimetype_map_
.clear();
153 for (size_t i
= 0; i
< app_list
.items().size(); ++i
) {
154 const google_apis::AppResource
& app
= *app_list
.items()[i
];
155 const std::string id
= app
.application_id();
157 google_apis::InstalledApp::IconList app_icons
;
158 google_apis::InstalledApp::IconList document_icons
;
159 for (size_t j
= 0; j
< app
.icons().size(); ++j
) {
160 const google_apis::DriveAppIcon
& icon
= *app
.icons()[j
];
161 if (icon
.icon_url().is_empty())
163 if (icon
.category() == google_apis::DriveAppIcon::APPLICATION
)
164 app_icons
.push_back(std::make_pair(icon
.icon_side_length(),
166 if (icon
.category() == google_apis::DriveAppIcon::DOCUMENT
)
167 document_icons
.push_back(std::make_pair(icon
.icon_side_length(),
171 all_apps_
[id
] = DriveAppInfo(app
.application_id(),
177 // TODO(kinaba): consider taking primary/secondary distinction into account.
178 AddAppSelectorList(app
.primary_mimetypes(), id
, &mimetype_map_
);
179 AddAppSelectorList(app
.secondary_mimetypes(), id
, &mimetype_map_
);
180 AddAppSelectorList(app
.primary_file_extensions(), id
, &extension_map_
);
181 AddAppSelectorList(app
.secondary_file_extensions(), id
, &extension_map_
);
185 void DriveAppRegistry::UninstallApp(const std::string
& app_id
,
186 const UninstallCallback
& callback
) {
187 DCHECK(!callback
.is_null());
189 drive_service_
->UninstallApp(app_id
,
190 base::Bind(&DriveAppRegistry::OnAppUninstalled
,
191 weak_ptr_factory_
.GetWeakPtr(),
196 void DriveAppRegistry::OnAppUninstalled(const std::string
& app_id
,
197 const UninstallCallback
& callback
,
198 google_apis::GDataErrorCode error
) {
199 if (error
== google_apis::HTTP_NO_CONTENT
) {
200 all_apps_
.erase(app_id
);
201 RemoveAppFromSelector(app_id
, &mimetype_map_
);
202 RemoveAppFromSelector(app_id
, &extension_map_
);
208 bool DriveAppRegistry::IsAppUninstallSupported() {
209 return google_apis::IsGoogleChromeAPIKeyUsed();
214 GURL
FindPreferredIcon(const google_apis::InstalledApp::IconList
& icons
,
215 int preferred_size
) {
219 google_apis::InstalledApp::IconList sorted_icons
= icons
;
220 std::sort(sorted_icons
.rbegin(), sorted_icons
.rend());
222 // Go forward while the size is larger or equal to preferred_size.
224 while (i
< sorted_icons
.size() && sorted_icons
[i
].first
>= preferred_size
)
226 return sorted_icons
[i
- 1].second
;