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 std::string
& product_id
,
60 const google_apis::InstalledApp::IconList
& app_icons
,
61 const google_apis::InstalledApp::IconList
& document_icons
,
62 const std::string
& app_name
,
63 const GURL
& create_url
,
66 product_id(product_id
),
68 document_icons(document_icons
),
70 create_url(create_url
),
71 is_removable(is_removable
) {
74 DriveAppInfo::~DriveAppInfo() {
77 DriveAppRegistry::DriveAppRegistry(DriveServiceInterface
* drive_service
)
78 : drive_service_(drive_service
),
80 weak_ptr_factory_(this) {
83 DriveAppRegistry::~DriveAppRegistry() {
86 void DriveAppRegistry::GetAppsForFile(
87 const base::FilePath::StringType
& file_extension
,
88 const std::string
& mime_type
,
89 std::vector
<DriveAppInfo
>* apps
) const {
90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
92 std::vector
<std::string
> matched_apps
;
93 if (!file_extension
.empty()) {
94 const std::string without_dot
=
95 base::FilePath(file_extension
.substr(1)).AsUTF8Unsafe();
96 FindAppsForSelector(without_dot
, extension_map_
, &matched_apps
);
98 if (!mime_type
.empty())
99 FindAppsForSelector(mime_type
, mimetype_map_
, &matched_apps
);
101 // Insert found Drive apps into |apps|, but skip duplicate results.
102 std::set
<std::string
> inserted_app_ids
;
103 for (size_t i
= 0; i
< matched_apps
.size(); ++i
) {
104 if (inserted_app_ids
.count(matched_apps
[i
]) == 0) {
105 inserted_app_ids
.insert(matched_apps
[i
]);
106 std::map
<std::string
, DriveAppInfo
>::const_iterator it
=
107 all_apps_
.find(matched_apps
[i
]);
108 DCHECK(it
!= all_apps_
.end());
109 apps
->push_back(it
->second
);
114 void DriveAppRegistry::GetAppList(std::vector
<DriveAppInfo
>* apps
) const {
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
118 for (std::map
<std::string
, DriveAppInfo
>::const_iterator
119 it
= all_apps_
.begin(); it
!= all_apps_
.end(); ++it
) {
120 apps
->push_back(it
->second
);
124 void DriveAppRegistry::Update() {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
127 if (is_updating_
) // There is already an update in progress.
131 drive_service_
->GetAppList(
132 base::Bind(&DriveAppRegistry::UpdateAfterGetAppList
,
133 weak_ptr_factory_
.GetWeakPtr()));
136 void DriveAppRegistry::UpdateAfterGetAppList(
137 google_apis::GDataErrorCode gdata_error
,
138 scoped_ptr
<google_apis::AppList
> app_list
) {
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
141 DCHECK(is_updating_
);
142 is_updating_
= false;
144 // Failed to fetch the data from the server. We can do nothing here.
145 if (gdata_error
!= google_apis::HTTP_SUCCESS
)
149 UpdateFromAppList(*app_list
);
152 void DriveAppRegistry::UpdateFromAppList(const google_apis::AppList
& app_list
) {
154 extension_map_
.clear();
155 mimetype_map_
.clear();
157 for (size_t i
= 0; i
< app_list
.items().size(); ++i
) {
158 const google_apis::AppResource
& app
= *app_list
.items()[i
];
159 const std::string id
= app
.application_id();
161 google_apis::InstalledApp::IconList app_icons
;
162 google_apis::InstalledApp::IconList document_icons
;
163 for (size_t j
= 0; j
< app
.icons().size(); ++j
) {
164 const google_apis::DriveAppIcon
& icon
= *app
.icons()[j
];
165 if (icon
.icon_url().is_empty())
167 if (icon
.category() == google_apis::DriveAppIcon::APPLICATION
)
168 app_icons
.push_back(std::make_pair(icon
.icon_side_length(),
170 if (icon
.category() == google_apis::DriveAppIcon::DOCUMENT
)
171 document_icons
.push_back(std::make_pair(icon
.icon_side_length(),
175 all_apps_
[id
] = DriveAppInfo(app
.application_id(),
183 // TODO(kinaba): consider taking primary/secondary distinction into account.
184 AddAppSelectorList(app
.primary_mimetypes(), id
, &mimetype_map_
);
185 AddAppSelectorList(app
.secondary_mimetypes(), id
, &mimetype_map_
);
186 AddAppSelectorList(app
.primary_file_extensions(), id
, &extension_map_
);
187 AddAppSelectorList(app
.secondary_file_extensions(), id
, &extension_map_
);
191 void DriveAppRegistry::UninstallApp(const std::string
& app_id
,
192 const UninstallCallback
& callback
) {
193 DCHECK(!callback
.is_null());
195 drive_service_
->UninstallApp(app_id
,
196 base::Bind(&DriveAppRegistry::OnAppUninstalled
,
197 weak_ptr_factory_
.GetWeakPtr(),
202 void DriveAppRegistry::OnAppUninstalled(const std::string
& app_id
,
203 const UninstallCallback
& callback
,
204 google_apis::GDataErrorCode error
) {
205 if (error
== google_apis::HTTP_NO_CONTENT
) {
206 all_apps_
.erase(app_id
);
207 RemoveAppFromSelector(app_id
, &mimetype_map_
);
208 RemoveAppFromSelector(app_id
, &extension_map_
);
214 bool DriveAppRegistry::IsAppUninstallSupported() {
215 return google_apis::IsGoogleChromeAPIKeyUsed();
220 GURL
FindPreferredIcon(const google_apis::InstalledApp::IconList
& icons
,
221 int preferred_size
) {
225 google_apis::InstalledApp::IconList sorted_icons
= icons
;
226 std::sort(sorted_icons
.rbegin(), sorted_icons
.rend());
228 // Go forward while the size is larger or equal to preferred_size.
230 while (i
< sorted_icons
.size() && sorted_icons
[i
].first
>= preferred_size
)
232 return sorted_icons
[i
- 1].second
;