Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(834)

Side by Side Diff: chrome/browser/ui/app_list/arc_app_list_prefs.cc

Issue 1413153007: arc-app-launcher: Minimal support for ARC app launcher. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: nit comment addressed Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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/ui/app_list/arc_app_list_prefs.h"
6
7 #include "base/files/file_util.h"
8 #include "base/prefs/scoped_user_pref_update.h"
9 #include "base/task_runner_util.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/app_list/arc_app_list_prefs_factory.h"
12 #include "chrome/common/pref_names.h"
13 #include "components/crx_file/id_util.h"
14 #include "components/pref_registry/pref_registry_syncable.h"
15 #include "content/public/browser/browser_thread.h"
16
17 namespace {
18
19 const char kName[] = "name";
20 const char kPackage[] = "package";
21 const char kActivity[] = "activity";
22
23 // Provider of write access to a dictionary storing ARC app prefs.
24 class ScopedArcAppListPrefUpdate : public DictionaryPrefUpdate {
25 public:
26 ScopedArcAppListPrefUpdate(PrefService* service, const std::string& id)
27 : DictionaryPrefUpdate(service, prefs::kArcApps),
28 id_(id) {}
29
30 ~ScopedArcAppListPrefUpdate() override {}
31
32 // DictionaryPrefUpdate overrides:
33 base::DictionaryValue* Get() override {
34 base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
35 base::DictionaryValue* app = nullptr;
36 if (!dict->GetDictionary(id_, &app)) {
37 app = new base::DictionaryValue();
38 dict->SetWithoutPathExpansion(id_, app);
39 }
40 return app;
41 }
42
43 private:
44 const std::string id_;
45
46 DISALLOW_COPY_AND_ASSIGN(ScopedArcAppListPrefUpdate);
47 };
48
49 bool InstallIconFromFileThread(const std::string& app_id,
50 ui::ScaleFactor scale_factor,
51 const base::FilePath& icon_path,
52 const std::vector<uint8>& content_png) {
53 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
54 DCHECK(!content_png.empty());
55
56 base::CreateDirectory(icon_path.DirName());
57
58 int wrote = base::WriteFile(icon_path,
59 reinterpret_cast<const char*>(&content_png[0]),
60 content_png.size());
61 if (wrote != static_cast<int>(content_png.size())) {
62 LOG(ERROR) << "Failed to write ARC icon file: " << icon_path.MaybeAsASCII()
63 << ".";
64 DCHECK(base::DeleteFile(icon_path, false));
65 return false;
66 }
67
68 return true;
69 }
70
71 } // namespace
72
73 // static
74 ArcAppListPrefs* ArcAppListPrefs::Create(const base::FilePath& base_path,
75 PrefService* prefs) {
76 return new ArcAppListPrefs(base_path, prefs);
77 }
78
79 // static
80 void ArcAppListPrefs::RegisterProfilePrefs(
81 user_prefs::PrefRegistrySyncable* registry) {
82 registry->RegisterDictionaryPref(
83 prefs::kArcApps,
84 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
85 }
86
87 // static
88 ArcAppListPrefs* ArcAppListPrefs::Get(content::BrowserContext* context) {
89 return ArcAppListPrefsFactory::GetInstance()->GetForBrowserContext(context);
90 }
91
92 // static
93 std::string ArcAppListPrefs::GetAppId(const std::string& package,
94 const std::string& activity) {
95 std::string input = package + "#" + activity;
96 return crx_file::id_util::GenerateId(input);
97 }
98
99 ArcAppListPrefs::ArcAppListPrefs(const base::FilePath& base_path,
100 PrefService* prefs)
101 : prefs_(prefs),
102 weak_ptr_factory_(this) {
103 base_path_ = base_path.AppendASCII(prefs::kArcApps);
104
105 arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
106 if (!bridge_service) {
107 LOG(ERROR) << "Bridge service is not available. Cannot init.";
108 return;
109 }
110
111 bridge_service->AddObserver(this);
112 OnStateChanged(bridge_service->state());
113 }
114
115 ArcAppListPrefs::~ArcAppListPrefs() {
116 arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
117 if (bridge_service) {
118 bridge_service->RemoveObserver(this);
119 }
120 }
121
122 base::FilePath ArcAppListPrefs::GetIconPath(
123 const std::string& app_id,
124 ui::ScaleFactor scale_factor) const {
125 base::FilePath app_path = base_path_.AppendASCII(app_id);
126 switch (scale_factor) {
127 case ui::SCALE_FACTOR_100P:
128 return app_path.AppendASCII("icon_100p.png");
129 case ui::SCALE_FACTOR_125P:
130 return app_path.AppendASCII("icon_125p.png");
131 case ui::SCALE_FACTOR_133P:
132 return app_path.AppendASCII("icon_133p.png");
133 case ui::SCALE_FACTOR_140P:
134 return app_path.AppendASCII("icon_140p.png");
135 case ui::SCALE_FACTOR_150P:
136 return app_path.AppendASCII("icon_150p.png");
137 case ui::SCALE_FACTOR_180P:
138 return app_path.AppendASCII("icon_180p.png");
139 case ui::SCALE_FACTOR_200P:
140 return app_path.AppendASCII("icon_200p.png");
141 case ui::SCALE_FACTOR_250P:
142 return app_path.AppendASCII("icon_250p.png");
143 case ui::SCALE_FACTOR_300P:
144 return app_path.AppendASCII("icon_300p.png");
145 default:
146 NOTREACHED();
147 return base::FilePath();
148 }
149 }
150
151 void ArcAppListPrefs::RequestIcon(const std::string& app_id,
152 ui::ScaleFactor scale_factor) {
153 if (!IsRegistered(app_id)) {
154 LOG(ERROR) << "Request to load icon for non-registered app: "
155 << app_id << ".";
156 return;
157 }
158
159 // In case app is not ready, defer this request.
160 if (!ready_apps_.count(app_id)) {
161 request_icon_deferred_[app_id] =
162 request_icon_deferred_[app_id] | 1 << scale_factor;
163 return;
164 }
165
166 arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
167 if (!bridge_service ||
168 bridge_service->state() != arc::ArcBridgeService::State::READY) {
169 LOG(ERROR) << "Request to load icon when bridge service is not ready: "
170 << app_id << ".";
171 return;
172 }
173
174 scoped_ptr<AppInfo> app_info = GetApp(app_id);
175 if (!app_info) {
176 LOG(ERROR) << "Failed to get app info: " << app_id << ".";
177 return;
178 }
179
180 bridge_service->RequestIcon(app_info->package,
181 app_info->activity,
182 static_cast<int>(scale_factor));
183 }
184
185 void ArcAppListPrefs::AddObserver(Observer* observer) {
186 observer_list_.AddObserver(observer);
187 }
188
189 void ArcAppListPrefs::RemoveObserver(Observer* observer) {
190 observer_list_.RemoveObserver(observer);
191 }
192
193 std::vector<std::string> ArcAppListPrefs::GetAppIds() const {
194 std::vector<std::string> ids;
195
196 // crx_file::id_util is de-factor utility for id generation.
197 const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
198 for (base::DictionaryValue::Iterator app_id(*apps);
199 !app_id.IsAtEnd(); app_id.Advance()) {
200 if (!crx_file::id_util::IdIsValid(app_id.key()))
201 continue;
202 ids.push_back(app_id.key());
203 }
204
205 return ids;
206 }
207
208 scoped_ptr<ArcAppListPrefs::AppInfo> ArcAppListPrefs::GetApp(
209 const std::string& app_id) const {
210 const base::DictionaryValue* app = nullptr;
211 const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
212 if (!apps ||
213 !apps->GetDictionaryWithoutPathExpansion(app_id, &app)) {
214 return scoped_ptr<AppInfo>();
215 }
216
217 scoped_ptr<AppInfo> app_info(new AppInfo);
218 app->GetString(kName, &app_info->name);
219 app->GetString(kPackage, &app_info->package);
220 app->GetString(kActivity, &app_info->activity);
221 app_info->ready = ready_apps_.count(app_id) > 0;
222
223 return app_info.Pass();
224 }
225
226 bool ArcAppListPrefs::IsRegistered(const std::string& app_id) {
227 const base::DictionaryValue* app = nullptr;
228 const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
229 if (!apps || !apps->GetDictionary(app_id, &app)) {
230 return false;
231 }
232 return true;
233 }
234
235 void ArcAppListPrefs::DisableAllApps() {
236 for (auto& app_id : ready_apps_) {
237 FOR_EACH_OBSERVER(Observer,
238 observer_list_,
239 OnAppReadyChanged(app_id, false));
240 }
241 ready_apps_.clear();
242 }
243
244 void ArcAppListPrefs::OnStateChanged(arc::ArcBridgeService::State state) {
245 if (state == arc::ArcBridgeService::State::READY) {
246 arc::ArcBridgeService::Get()->RefreshApps();
247 } else {
248 DisableAllApps();
249 }
250 }
251
252 void ArcAppListPrefs::OnAppReady(const std::string& name,
253 const std::string& package,
254 const std::string& activity) {
255 if (name.empty() || package.empty() || activity.empty()) {
256 LOG(ERROR) << "Name, package and activity cannot be empty.";
257 return;
258 }
259 std::string app_id = GetAppId(package, activity);
260 bool was_registered = IsRegistered(app_id);
261
262 ScopedArcAppListPrefUpdate update(prefs_, app_id);
263 base::DictionaryValue* app_dict = update.Get();
264 app_dict->SetString(kName, name);
265 app_dict->SetString(kPackage, package);
266 app_dict->SetString(kActivity, activity);
267
268 // From now, app is ready.
269 if (!ready_apps_.count(app_id)) {
270 ready_apps_.insert(app_id);
271 }
272
273 if (was_registered) {
274 FOR_EACH_OBSERVER(Observer,
275 observer_list_,
276 OnAppReadyChanged(app_id, true));
277 } else {
278 AppInfo app_info;
279 app_info.name = name;
280 app_info.package = package;
281 app_info.activity = activity;
282 app_info.ready = true;
283 FOR_EACH_OBSERVER(Observer,
284 observer_list_,
285 OnAppRegistered(app_id, app_info));
286 }
287
288 std::map<std::string, uint32>::iterator deferred_icons =
289 request_icon_deferred_.find(app_id);
290 if (deferred_icons != request_icon_deferred_.end()) {
291 for (uint32 i = ui::SCALE_FACTOR_100P; i < ui::NUM_SCALE_FACTORS; ++i) {
292 if (deferred_icons->second & (1 << i)) {
293 RequestIcon(app_id, static_cast<ui::ScaleFactor>(i));
294 }
295 }
296 request_icon_deferred_.erase(deferred_icons);
297 }
298 }
299
300 void ArcAppListPrefs::OnAppsRefreshed(
301 const std::vector<std::string>& names,
302 const std::vector<std::string>& packages,
303 const std::vector<std::string>& activities) {
304 if (names.size() != packages.size() || names.size() != activities.size()) {
305 LOG(ERROR) << "Name, package and activity must be the same size.";
306 return;
307 }
308
309 std::set<std::string> old_ready_apps;
310 old_ready_apps.swap(ready_apps_);
311
312 for (size_t i = 0; i < names.size(); ++i) {
313 OnAppReady(names[i], packages[i], activities[i]);
314 }
315
316 // Detect unavailable apps after current refresh.
317 for (auto& app_id : old_ready_apps) {
elijahtaylor (use chromium) 2015/11/19 05:52:00 this is a little unexpected to me. Should apps ge
khmel1 2015/11/19 17:11:41 There is possible scenario when user has appA and
elijahtaylor (use chromium) 2015/11/19 17:45:49 This is very nuanced and I think what you have is
318 if (!ready_apps_.count(app_id)) {
319 FOR_EACH_OBSERVER(Observer,
320 observer_list_,
321 OnAppReadyChanged(app_id, false));
322 }
323 }
324 }
325
326 void ArcAppListPrefs::OnAppIcon(const std::string& package,
327 const std::string& activity,
328 int scale_factor,
329 const std::vector<uint8_t>& icon_png_data) {
330 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
331 DCHECK(!icon_png_data.empty());
332 DCHECK(scale_factor >= ui::SCALE_FACTOR_100P &&
333 scale_factor < ui::NUM_SCALE_FACTORS);
334
335 std::string app_id = GetAppId(package, activity);
336 if (!IsRegistered(app_id)) {
337 LOG(ERROR) << "Request to update icon for non-registered app: " << app_id;
338 return;
339 }
340
341 InstallIcon(app_id,
342 static_cast<ui::ScaleFactor>(scale_factor),
343 icon_png_data);
344 }
345
346
347 void ArcAppListPrefs::InstallIcon(const std::string& app_id,
348 ui::ScaleFactor scale_factor,
349 const std::vector<uint8>& content_png) {
350
351 base::FilePath icon_path = GetIconPath(app_id, scale_factor);
352 base::PostTaskAndReplyWithResult(content::BrowserThread::GetBlockingPool(),
353 FROM_HERE,
354 base::Bind(&InstallIconFromFileThread,
355 app_id,
356 scale_factor,
357 icon_path,
358 content_png),
359 base::Bind(&ArcAppListPrefs::OnIconInstalled,
360 weak_ptr_factory_.GetWeakPtr(),
361 app_id,
362 scale_factor));
363 }
364
365 void ArcAppListPrefs::OnIconInstalled(const std::string& app_id,
366 ui::ScaleFactor scale_factor,
367 bool install_succeed) {
368 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
369 if (!install_succeed) {
370 return;
371 }
372
373 FOR_EACH_OBSERVER(Observer,
374 observer_list_,
375 OnAppIconUpdated(app_id, scale_factor));
376 }
377
378 ArcAppListPrefs::AppInfo::AppInfo()
379 : ready(false) {
380 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698