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

Side by Side Diff: chrome/browser/ui/app_list/arc_app_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: switch to new IPC 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_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_prefs_factory.h"
12 #include "components/crx_file/id_util.h"
13 #include "components/pref_registry/pref_registry_syncable.h"
14 #include "content/public/browser/browser_thread.h"
15
16 namespace {
17
18 const char kArcApps[] = "arcapps";
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 ScopedArcAppPrefUpdate : public DictionaryPrefUpdate {
25 public:
26 ScopedArcAppPrefUpdate(PrefService* service, const std::string& id)
27 : DictionaryPrefUpdate(service, kArcApps),
28 id_(id) {}
29
30 ~ScopedArcAppPrefUpdate() override {}
31
32 // DictionaryPrefUpdate overrides:
33 base::DictionaryValue* Get() override {
34 base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
35 base::DictionaryValue* app = NULL;
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(ScopedArcAppPrefUpdate);
47 };
48
49 } // namespace
50
51 // static
52 ArcAppPrefs* ArcAppPrefs::Create(content::BrowserContext* browser_context,
53 const base::FilePath& base_path,
54 PrefService* prefs) {
55 return new ArcAppPrefs(browser_context, base_path, prefs);
56 }
57
58 // static
59 void ArcAppPrefs::RegisterProfilePrefs(
60 user_prefs::PrefRegistrySyncable* registry) {
61 registry->RegisterDictionaryPref(
62 kArcApps,
xiyuan 2015/11/11 22:15:51 kArcApps should be in chrome/common/pref_names.h
khmel1 2015/11/12 08:05:30 Done.
63 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
xiyuan 2015/11/11 22:15:50 ArcAppPrefs looks like a local cache to store app
khmel1 2015/11/12 08:05:30 One of the next idea is to use sync-able feature t
xiyuan 2015/11/12 17:32:44 Acknowledged. Thanks for the explanation.
elijahtaylor1 2015/11/13 01:56:00 Just chiming in that yes we do want to sync this i
64 }
65
66 // static
67 ArcAppPrefs* ArcAppPrefs::Get(content::BrowserContext* context) {
68 return ArcAppPrefsFactory::GetInstance()->GetForBrowserContext(context);
69 }
70
71 // static
72 std::string ArcAppPrefs::GetAppId(const std::string& package,
73 const std::string& activity) {
74 std::string input = package + "#" + activity;
75 return crx_file::id_util::GenerateId(input);
xiyuan 2015/11/11 22:15:50 nit: App list does not assume the format of the id
khmel1 2015/11/12 08:05:30 One of the reason I used this generator is '.' in
xiyuan 2015/11/12 17:32:44 Acknowledged.
76 }
77
78 ArcAppPrefs::ArcAppPrefs(content::BrowserContext* browser_context,
79 const base::FilePath& base_path,
80 PrefService* prefs)
81 : browser_context_(browser_context),
xiyuan 2015/11/11 22:15:50 |browser_context_| seems not used.
khmel1 2015/11/12 08:05:30 Yes, we use here only root folder for profile.
82 prefs_(prefs) {
83 base_path_ = base_path.AppendASCII(kArcApps);
84
85 arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
86 if (!bridge_service) {
87 LOG(ERROR) << "Bridge service is not available. Cannot init.";
88 return;
89 }
90
91 bridge_service->AddObserver(this);
92 if (bridge_service->state() == arc::ArcBridgeService::State::READY) {
xiyuan 2015/11/11 22:15:51 nit: How about doing "OnStateChanged(bridge_servic
khmel1 2015/11/12 08:05:30 Personally I prefer to do but was not sure that is
93 bridge_service->RefreshApps();
94 }
95 }
96
97 ArcAppPrefs::~ArcAppPrefs() {
98 arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
99 if (!bridge_service) {
100 LOG(ERROR) << "Bridge service is not available. Cannot release.";
xiyuan 2015/11/11 22:15:51 Do we know how ArcBridgeService starts and shuts d
khmel1 2015/11/12 08:05:31 This CL(1412863004) is still under review. But it
xiyuan 2015/11/12 17:32:44 Thanks for the CL reference. Yep, CL(1412863004) i
101 return;
102 }
103 bridge_service->RemoveObserver(this);
104 }
105
106 base::FilePath ArcAppPrefs::GetIconPath(const std::string& app_id,
107 ui::ScaleFactor scale_factor) const {
108 base::FilePath app_path = base_path_.AppendASCII(app_id);
109 switch (scale_factor) {
110 case ui::SCALE_FACTOR_100P:
111 return app_path.AppendASCII("icon_100p.png");
112 case ui::SCALE_FACTOR_125P:
113 return app_path.AppendASCII("icon_125p.png");
114 case ui::SCALE_FACTOR_133P:
115 return app_path.AppendASCII("icon_133p.png");
116 case ui::SCALE_FACTOR_140P:
117 return app_path.AppendASCII("icon_140p.png");
118 case ui::SCALE_FACTOR_150P:
119 return app_path.AppendASCII("icon_150p.png");
120 case ui::SCALE_FACTOR_180P:
121 return app_path.AppendASCII("icon_180p.png");
122 case ui::SCALE_FACTOR_200P:
123 return app_path.AppendASCII("icon_200p.png");
124 case ui::SCALE_FACTOR_250P:
125 return app_path.AppendASCII("icon_250p.png");
126 case ui::SCALE_FACTOR_300P:
127 return app_path.AppendASCII("icon_300p.png");
128 default:
129 NOTREACHED();
130 return base::FilePath();
131 }
132 }
133
134 void ArcAppPrefs::RequestIcon(const std::string& app_id,
135 ui::ScaleFactor scale_factor) {
136 if (!IsRegistered(app_id)) {
137 LOG(ERROR) << "Request to load icon for non-registered app: "
138 << app_id << ".";
139 return;
140 }
141
142 // In case app is not ready, defer this request.
143 if (!ready_apps_.count(app_id)) {
144 request_icon_deferred_[app_id] =
145 request_icon_deferred_[app_id] | 1 << scale_factor;
146 return;
147 }
148
149 arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
150 if (!bridge_service ||
151 bridge_service->state() != arc::ArcBridgeService::State::READY) {
152 LOG(ERROR) << "Request to load icon when bridge service is not ready: "
153 << app_id << ".";
154 return;
155 }
156
157 scoped_ptr<AppInfo> app_info = GetApp(app_id);
158 if (!app_info) {
159 LOG(ERROR) << "Failed to get app info: " << app_id << ".";
160 return;
161 }
162
163 bridge_service->RequestIcon(app_info->package,
164 app_info->activity,
165 static_cast<int>(scale_factor));
166 }
167
168 void ArcAppPrefs::AddObserver(Observer* observer) {
169 observer_list_.AddObserver(observer);
170 }
171
172 void ArcAppPrefs::RemoveObserver(Observer* observer) {
173 observer_list_.RemoveObserver(observer);
174 }
175
176 std::vector<std::string> ArcAppPrefs::GetAppIds() const {
177 std::vector<std::string> ids;
178
179 // crx_file::id_util is de-factor utility for id generation.
180 const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps);
181 for (base::DictionaryValue::Iterator app_id(*apps);
182 !app_id.IsAtEnd(); app_id.Advance()) {
183 if (!crx_file::id_util::IdIsValid(app_id.key()))
184 continue;
185 ids.push_back(app_id.key());
186 }
187
188 return ids;
189 }
190
191 scoped_ptr<ArcAppPrefs::AppInfo> ArcAppPrefs::GetApp(
192 const std::string& app_id) const {
193 const base::DictionaryValue* app = NULL;
194 const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps);
195 if (!apps ||
196 !apps->GetDictionaryWithoutPathExpansion(app_id, &app)) {
197 return scoped_ptr<AppInfo>();
198 }
199
200 scoped_ptr<AppInfo> app_info(new AppInfo);
201 app->GetString(kName, &app_info->name);
202 app->GetString(kPackage, &app_info->package);
203 app->GetString(kActivity, &app_info->activity);
204 app_info->ready = ready_apps_.count(app_id) > 0;
205
206 return app_info.Pass();
207 }
208
209 bool ArcAppPrefs::IsRegistered(const std::string& app_id) {
210 const base::DictionaryValue* app = NULL;
211 const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps);
212 if (!apps || !apps->GetDictionary(app_id, &app)) {
213 return false;
214 }
215 return true;
216 }
217
218 void ArcAppPrefs::DisableAllApps() {
219 std::set<std::string>::const_iterator it;
220 for (it = ready_apps_.begin(); it != ready_apps_.end(); ++it) {
xiyuan 2015/11/11 22:15:51 nit: for (auto& app_id : ready_apps_)
khmel1 2015/11/12 08:05:30 Done.
221 const std::string& app_id = *it;
222 FOR_EACH_OBSERVER(Observer,
223 observer_list_,
224 OnAppReady(app_id, false));
225 }
226 ready_apps_.clear();
227 }
228
229 void ArcAppPrefs::OnStateChanged(arc::ArcBridgeService::State state) {
230 if (state == arc::ArcBridgeService::State::READY) {
231 arc::ArcBridgeService::Get()->RefreshApps();
232 } else {
233 DisableAllApps();
234 }
235 }
236
237 void ArcAppPrefs::OnAppReady(const std::string& name,
238 const std::string& package) {
239 std::string app_id = GetAppId(package, "");
240 bool was_registered = IsRegistered(app_id);
241
242 ScopedArcAppPrefUpdate update(prefs_, app_id);
243 base::DictionaryValue* app_dict = update.Get();
244 app_dict->SetString(kName, name);
245 app_dict->SetString(kPackage, package);
246 app_dict->SetString(kActivity, "");
247
248 // From now, app is ready.
249 if (!ready_apps_.count(app_id)) {
250 ready_apps_.insert(app_id);
251 }
252
253 if (was_registered) {
254 FOR_EACH_OBSERVER(Observer,
255 observer_list_,
256 OnAppReady(app_id, true));
257 } else {
258 AppInfo app_info;
259 app_info.name = name;
260 app_info.package = package;
261 app_info.activity = "";
262 app_info.ready = true;
263 FOR_EACH_OBSERVER(Observer,
264 observer_list_,
265 OnAppRegistered(app_id, app_info));
266 }
267
268 std::map<std::string, uint32>::iterator deferred_icons =
269 request_icon_deferred_.find(app_id);
270 if (deferred_icons != request_icon_deferred_.end()) {
271 for (uint32 i = ui::SCALE_FACTOR_100P; i < ui::NUM_SCALE_FACTORS; ++i) {
272 if (deferred_icons->second & (1 << i)) {
273 RequestIcon(app_id, static_cast<ui::ScaleFactor>(i));
274 }
275 }
276 request_icon_deferred_.erase(deferred_icons);
277 }
278 }
279
280 void ArcAppPrefs::OnAppsRefreshed(const std::vector<std::string>& names,
281 const std::vector<std::string>& packages) {
282 std::set<std::string> old_ready_apps_;
xiyuan 2015/11/11 22:15:51 nit: old_ready_apps_ -> old_ready_apps
khmel1 2015/11/12 08:05:30 Done.
283 old_ready_apps_.swap(ready_apps_);
284
285 for (size_t i = 0; i < names.size(); ++i) {
286 OnAppReady(names[i], packages[i]);
287 }
288
289 // Detect unavailable apps after current refresh.
290 std::set<std::string>::const_iterator it;
291 for (it = old_ready_apps_.begin(); it != old_ready_apps_.end(); ++it) {
xiyuan 2015/11/11 22:15:50 nit: for (auto& app_id : old_ready_apps)
khmel1 2015/11/12 08:05:30 Done.
292 const std::string& app_id = *it;
293 if (!ready_apps_.count(app_id)) {
294 FOR_EACH_OBSERVER(Observer,
295 observer_list_,
296 OnAppReady(app_id, false));
297 }
298 }
299 }
300
301 void ArcAppPrefs::OnAppIcon(const std::string& package,
302 const std::string& activity,
303 int density,
304 const std::vector<uint8_t>& icon_png_data) {
305 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
306 DCHECK(!icon_png_data.empty());
307 DCHECK(density >= ui::SCALE_FACTOR_100P && density < ui::NUM_SCALE_FACTORS);
308
309 std::string app_id = GetAppId(package, activity);
310 if (!IsRegistered(app_id)) {
311 LOG(ERROR) << "Request to update icon for non-registered app: " << app_id;
312 return;
313 }
314
315 InstallIcon(app_id, static_cast<ui::ScaleFactor>(density), icon_png_data);
316 }
317
318
319 void ArcAppPrefs::InstallIcon(const std::string& app_id,
320 ui::ScaleFactor scale_factor,
321 const std::vector<uint8>& content_png) {
322 base::Closure task = base::Bind(&ArcAppPrefs::InstallIconFromFileThread,
323 base::Unretained(this),
xiyuan 2015/11/11 22:15:50 base::Unretained is dangerous. Add a WeakPtrFactor
khmel1 2015/11/12 08:05:30 Done.
324 app_id,
325 scale_factor,
326 content_png);
327 content::BrowserThread::PostTask(content::BrowserThread::FILE,
xiyuan 2015/11/11 22:15:50 Use BrowserThrad::GetBlockingPool instead of file
khmel1 2015/11/12 08:05:30 Done.
328 FROM_HERE,
329 task);
330 }
331
332 void ArcAppPrefs::InstallIconFromFileThread(
333 const std::string& app_id,
334 ui::ScaleFactor scale_factor,
335 const std::vector<uint8>& content_png) {
336 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
337 DCHECK(!content_png.empty());
338
339 base::FilePath app_path = base_path_.AppendASCII(app_id);
340 base::CreateDirectory(app_path);
341 base::FilePath icon_path = GetIconPath(app_id, scale_factor);
342
343 int wrote = base::WriteFile(icon_path,
344 reinterpret_cast<const char*>(&content_png[0]),
345 content_png.size());
346 DCHECK(wrote == static_cast<int>(content_png.size()));
xiyuan 2015/11/11 22:15:51 nit: DCHECK_EQ(wrote, static_cast<int>(content_png
khmel1 2015/11/12 08:05:30 As I understand potentially we may get situation w
xiyuan 2015/11/12 17:32:44 Acknowledged.
347
348 base::Closure task = base::Bind(&ArcAppPrefs::OnIconInstalled,
349 base::Unretained(this),
xiyuan 2015/11/11 22:15:51 ditto
khmel1 2015/11/12 08:05:30 Done.
350 app_id,
351 scale_factor);
352 content::BrowserThread::PostTask(content::BrowserThread::UI,
353 FROM_HERE,
354 task);
355 }
356
357 void ArcAppPrefs::OnIconInstalled(const std::string& app_id,
358 ui::ScaleFactor scale_factor) {
359 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
360
361 FOR_EACH_OBSERVER(Observer,
362 observer_list_,
363 OnAppIconUpdated(app_id, scale_factor));
364 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698