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 "components/drive/drive_app_registry.h"
11 #include "base/callback.h"
12 #include "base/files/file_path.h"
13 #include "components/drive/drive_app_registry_observer.h"
14 #include "components/drive/service/drive_service_interface.h"
15 #include "google_apis/drive/drive_api_parser.h"
16 #include "google_apis/google_api_keys.h"
20 // Add {selector -> app_id} mapping to |map|.
21 void AddAppSelectorList(const ScopedVector
<std::string
>& selectors
,
22 const std::string
& app_id
,
23 std::multimap
<std::string
, std::string
>* map
) {
24 for (size_t i
= 0; i
< selectors
.size(); ++i
)
25 map
->insert(std::make_pair(*selectors
[i
], app_id
));
28 // Append list of app ids in |map| looked up by |selector| to |matched_apps|.
29 void FindAppsForSelector(const std::string
& selector
,
30 const std::multimap
<std::string
, std::string
>& map
,
31 std::vector
<std::string
>* matched_apps
) {
32 typedef std::multimap
<std::string
, std::string
>::const_iterator iterator
;
33 std::pair
<iterator
, iterator
> range
= map
.equal_range(selector
);
34 for (iterator it
= range
.first
; it
!= range
.second
; ++it
)
35 matched_apps
->push_back(it
->second
);
38 void RemoveAppFromSelector(const std::string
& app_id
,
39 std::multimap
<std::string
, std::string
>* map
) {
40 typedef std::multimap
<std::string
, std::string
>::iterator iterator
;
41 for (iterator it
= map
->begin(); it
!= map
->end(); ) {
43 if (now
->second
== app_id
)
52 DriveAppInfo::DriveAppInfo() {
55 DriveAppInfo::DriveAppInfo(
56 const std::string
& app_id
,
57 const std::string
& product_id
,
58 const IconList
& app_icons
,
59 const IconList
& document_icons
,
60 const std::string
& app_name
,
61 const GURL
& create_url
,
64 product_id(product_id
),
66 document_icons(document_icons
),
68 create_url(create_url
),
69 is_removable(is_removable
) {
72 DriveAppInfo::~DriveAppInfo() {
75 DriveAppRegistry::DriveAppRegistry(DriveServiceInterface
* drive_service
)
76 : drive_service_(drive_service
),
78 weak_ptr_factory_(this) {
81 DriveAppRegistry::~DriveAppRegistry() {
84 void DriveAppRegistry::GetAppsForFile(
85 const base::FilePath::StringType
& file_extension
,
86 const std::string
& mime_type
,
87 std::vector
<DriveAppInfo
>* apps
) const {
88 DCHECK(thread_checker_
.CalledOnValidThread());
90 std::vector
<std::string
> matched_apps
;
91 if (!file_extension
.empty()) {
92 const std::string without_dot
=
93 base::FilePath(file_extension
.substr(1)).AsUTF8Unsafe();
94 FindAppsForSelector(without_dot
, extension_map_
, &matched_apps
);
96 if (!mime_type
.empty())
97 FindAppsForSelector(mime_type
, mimetype_map_
, &matched_apps
);
99 // Insert found Drive apps into |apps|, but skip duplicate results.
100 std::set
<std::string
> inserted_app_ids
;
101 for (size_t i
= 0; i
< matched_apps
.size(); ++i
) {
102 if (inserted_app_ids
.count(matched_apps
[i
]) == 0) {
103 inserted_app_ids
.insert(matched_apps
[i
]);
104 std::map
<std::string
, DriveAppInfo
>::const_iterator it
=
105 all_apps_
.find(matched_apps
[i
]);
106 DCHECK(it
!= all_apps_
.end());
107 apps
->push_back(it
->second
);
112 void DriveAppRegistry::GetAppList(std::vector
<DriveAppInfo
>* apps
) const {
113 DCHECK(thread_checker_
.CalledOnValidThread());
116 for (std::map
<std::string
, DriveAppInfo
>::const_iterator
117 it
= all_apps_
.begin(); it
!= all_apps_
.end(); ++it
) {
118 apps
->push_back(it
->second
);
122 void DriveAppRegistry::Update() {
123 DCHECK(thread_checker_
.CalledOnValidThread());
125 if (is_updating_
) // There is already an update in progress.
129 drive_service_
->GetAppList(
130 base::Bind(&DriveAppRegistry::UpdateAfterGetAppList
,
131 weak_ptr_factory_
.GetWeakPtr()));
134 void DriveAppRegistry::UpdateAfterGetAppList(
135 google_apis::DriveApiErrorCode gdata_error
,
136 scoped_ptr
<google_apis::AppList
> app_list
) {
137 DCHECK(thread_checker_
.CalledOnValidThread());
139 DCHECK(is_updating_
);
140 is_updating_
= false;
142 // Failed to fetch the data from the server. We can do nothing here.
143 if (gdata_error
!= google_apis::HTTP_SUCCESS
)
147 UpdateFromAppList(*app_list
);
150 void DriveAppRegistry::UpdateFromAppList(const google_apis::AppList
& app_list
) {
152 extension_map_
.clear();
153 mimetype_map_
.clear();
155 for (size_t i
= 0; i
< app_list
.items().size(); ++i
) {
156 const google_apis::AppResource
& app
= *app_list
.items()[i
];
157 const std::string id
= app
.application_id();
159 DriveAppInfo::IconList app_icons
;
160 DriveAppInfo::IconList document_icons
;
161 for (size_t j
= 0; j
< app
.icons().size(); ++j
) {
162 const google_apis::DriveAppIcon
& icon
= *app
.icons()[j
];
163 if (icon
.icon_url().is_empty())
165 if (icon
.category() == google_apis::DriveAppIcon::APPLICATION
)
166 app_icons
.push_back(std::make_pair(icon
.icon_side_length(),
168 if (icon
.category() == google_apis::DriveAppIcon::DOCUMENT
)
169 document_icons
.push_back(std::make_pair(icon
.icon_side_length(),
173 all_apps_
[id
] = DriveAppInfo(app
.application_id(),
181 // TODO(kinaba): consider taking primary/secondary distinction into account.
182 AddAppSelectorList(app
.primary_mimetypes(), id
, &mimetype_map_
);
183 AddAppSelectorList(app
.secondary_mimetypes(), id
, &mimetype_map_
);
184 AddAppSelectorList(app
.primary_file_extensions(), id
, &extension_map_
);
185 AddAppSelectorList(app
.secondary_file_extensions(), id
, &extension_map_
);
188 FOR_EACH_OBSERVER(DriveAppRegistryObserver
,
190 OnDriveAppRegistryUpdated());
193 void DriveAppRegistry::AddObserver(DriveAppRegistryObserver
* observer
) {
194 observers_
.AddObserver(observer
);
197 void DriveAppRegistry::RemoveObserver(DriveAppRegistryObserver
* observer
) {
198 observers_
.RemoveObserver(observer
);
201 void DriveAppRegistry::UninstallApp(const std::string
& app_id
,
202 const UninstallCallback
& callback
) {
203 DCHECK(!callback
.is_null());
205 drive_service_
->UninstallApp(app_id
,
206 base::Bind(&DriveAppRegistry::OnAppUninstalled
,
207 weak_ptr_factory_
.GetWeakPtr(),
212 void DriveAppRegistry::OnAppUninstalled(const std::string
& app_id
,
213 const UninstallCallback
& callback
,
214 google_apis::DriveApiErrorCode error
) {
215 if (error
== google_apis::HTTP_NO_CONTENT
) {
216 all_apps_
.erase(app_id
);
217 RemoveAppFromSelector(app_id
, &mimetype_map_
);
218 RemoveAppFromSelector(app_id
, &extension_map_
);
224 bool DriveAppRegistry::IsAppUninstallSupported() {
225 return google_apis::IsGoogleChromeAPIKeyUsed();
230 GURL
FindPreferredIcon(const DriveAppInfo::IconList
& icons
,
231 int preferred_size
) {
235 DriveAppInfo::IconList sorted_icons
= icons
;
236 std::sort(sorted_icons
.rbegin(), sorted_icons
.rend());
238 // Go forward while the size is larger or equal to preferred_size.
240 while (i
< sorted_icons
.size() && sorted_icons
[i
].first
>= preferred_size
)
242 return sorted_icons
[i
- 1].second
;