OLD | NEW |
---|---|
(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 "chromeos/dbus/dbus_thread_manager.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 kArcApps[] = "arcapps"; | |
20 const char kName[] = "name"; | |
21 const char kPackage[] = "package"; | |
22 const char kActivity[] = "activity"; | |
23 const char kIcons[] = "icons"; | |
24 | |
25 // Provider of write access to a dictionary storing arc app prefs. | |
26 class ScopedArcAppPrefUpdate : public DictionaryPrefUpdate { | |
27 public: | |
28 ScopedArcAppPrefUpdate(PrefService* service, const std::string& id) | |
29 : DictionaryPrefUpdate(service, kArcApps), | |
30 id_(id) {} | |
31 | |
32 ~ScopedArcAppPrefUpdate() override {} | |
33 | |
34 // DictionaryPrefUpdate overrides: | |
35 base::DictionaryValue* Get() override { | |
36 base::DictionaryValue* dict = DictionaryPrefUpdate::Get(); | |
37 base::DictionaryValue* app = NULL; | |
38 if (!dict->GetDictionary(id_, &app)) { | |
39 app = new base::DictionaryValue(); | |
40 dict->SetWithoutPathExpansion(id_, app); | |
41 } | |
42 return app; | |
43 } | |
44 | |
45 private: | |
46 const std::string id_; | |
47 | |
48 DISALLOW_COPY_AND_ASSIGN(ScopedArcAppPrefUpdate); | |
49 }; | |
50 | |
51 base::FilePath GetIconPath(const base::FilePath& base_path, | |
52 ui::ScaleFactor scale_factor) { | |
53 switch (scale_factor) { | |
elijahtaylor1
2015/10/28 06:32:39
it's not clear what all of these icon sizes are fo
khmel1
2015/10/29 08:12:18
Required icon is determined by scale factor of Dis
| |
54 case ui::SCALE_FACTOR_100P: | |
55 return base_path.AppendASCII("icon_100p.png"); | |
56 case ui::SCALE_FACTOR_125P: | |
57 return base_path.AppendASCII("icon_125p.png"); | |
58 case ui::SCALE_FACTOR_133P: | |
59 return base_path.AppendASCII("icon_133p.png"); | |
60 case ui::SCALE_FACTOR_140P: | |
61 return base_path.AppendASCII("icon_140p.png"); | |
62 case ui::SCALE_FACTOR_150P: | |
63 return base_path.AppendASCII("icon_150p.png"); | |
64 case ui::SCALE_FACTOR_180P: | |
65 return base_path.AppendASCII("icon_180p.png"); | |
66 case ui::SCALE_FACTOR_200P: | |
67 return base_path.AppendASCII("icon_200p.png"); | |
68 case ui::SCALE_FACTOR_250P: | |
69 return base_path.AppendASCII("icon_250p.png"); | |
70 case ui::SCALE_FACTOR_300P: | |
71 return base_path.AppendASCII("icon_300p.png"); | |
72 default: | |
73 CHECK(false); | |
74 return base::FilePath(); | |
75 } | |
76 } | |
77 | |
78 } // namespace | |
79 | |
80 // static | |
81 ArcAppPrefs* ArcAppPrefs::Create(content::BrowserContext* browser_context, | |
82 const base::FilePath& base_path, | |
83 PrefService* prefs) { | |
84 return new ArcAppPrefs(browser_context, base_path, prefs); | |
85 } | |
86 | |
87 // static | |
88 void ArcAppPrefs::RegisterProfilePrefs( | |
89 user_prefs::PrefRegistrySyncable* registry) { | |
90 registry->RegisterDictionaryPref( | |
91 kArcApps, | |
92 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); | |
93 } | |
94 | |
95 // static | |
96 ArcAppPrefs* ArcAppPrefs::Get(content::BrowserContext* context) { | |
97 return ArcAppPrefsFactory::GetInstance()->GetForBrowserContext(context); | |
98 } | |
99 | |
100 // static | |
101 std::string ArcAppPrefs::GetAppId(const std::string& package, | |
102 const std::string& activity) { | |
103 std::string input = package + "#" + activity; | |
104 return crx_file::id_util::GenerateId(input); | |
elijahtaylor1
2015/10/28 06:32:39
does this need to be a CRX style ID? It would be
khmel1
2015/10/29 08:12:18
My first impl was the same as you suggested. Howev
| |
105 } | |
106 | |
107 ArcAppPrefs::ArcAppPrefs(content::BrowserContext* browser_context, | |
108 const base::FilePath& base_path, | |
109 PrefService* prefs) | |
110 : browser_context_(browser_context), | |
111 prefs_(prefs) { | |
elijahtaylor1
2015/10/28 06:32:39
alignment
khmel1
2015/10/29 08:12:18
Done.
| |
112 base_path_ = base_path.AppendASCII(kArcApps); | |
113 | |
114 chromeos::DBusThreadManager::Get()->GetArcBridgeClient()-> | |
115 AddAppObserver(this); | |
116 chromeos::DBusThreadManager::Get()->GetArcBridgeClient()->Refresh(); | |
117 } | |
118 | |
119 ArcAppPrefs::~ArcAppPrefs() { | |
120 chromeos::DBusThreadManager::Get()->GetArcBridgeClient()-> | |
121 RemoveAppObserver(this); | |
122 } | |
123 | |
124 void ArcAppPrefs::AddObserver(Observer* observer) { | |
125 observer_list_.AddObserver(observer); | |
126 } | |
127 | |
128 void ArcAppPrefs::RemoveObserver(Observer* observer) { | |
129 observer_list_.RemoveObserver(observer); | |
130 } | |
131 | |
132 std::vector<std::string> ArcAppPrefs::GetAppIds() const { | |
133 std::vector<std::string> ids; | |
134 | |
135 const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps); | |
136 for (base::DictionaryValue::Iterator app_id(*apps); | |
137 !app_id.IsAtEnd(); app_id.Advance()) { | |
138 if (!crx_file::id_util::IdIsValid(app_id.key())) | |
139 continue; | |
140 ids.push_back(app_id.key()); | |
141 } | |
142 | |
143 return ids; | |
144 } | |
145 | |
146 scoped_ptr<ArcAppPrefs::AppInfo> ArcAppPrefs::GetApp( | |
147 const std::string& app_id) const { | |
148 const base::DictionaryValue* app = NULL; | |
149 const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps); | |
150 if (!apps || | |
151 !apps->GetDictionaryWithoutPathExpansion(app_id, &app)) | |
152 return scoped_ptr<AppInfo>(); | |
153 | |
154 scoped_ptr<AppInfo> app_info(new AppInfo); | |
155 app->GetString(kName, &app_info->name); | |
156 app->GetString(kPackage, &app_info->package); | |
157 app->GetString(kActivity, &app_info->activity); | |
158 app_info->enabled = enable_apps_.count(app_id) > 0; | |
159 | |
160 base::FilePath app_path = base_path_.AppendASCII(app_id); | |
161 | |
162 int icon_flags = 0; | |
163 if (app->GetInteger(kIcons, &icon_flags)) { | |
164 for (int i = ui::SCALE_FACTOR_100P; i < ui::NUM_SCALE_FACTORS; ++i) { | |
165 if (icon_flags & (1 << i)) { | |
166 IconInfo icon_info; | |
167 icon_info.scale_factor = static_cast<ui::ScaleFactor>(i); | |
168 icon_info.path = GetIconPath(app_path, icon_info.scale_factor); | |
169 app_info->icons.push_back(icon_info); | |
170 } | |
171 } | |
172 } | |
173 | |
174 return app_info.Pass(); | |
175 } | |
176 | |
177 bool ArcAppPrefs::IsRegistered(const std::string& app_id) { | |
178 const base::DictionaryValue* app = NULL; | |
179 const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps); | |
180 if (!apps || !apps->GetDictionary(app_id, &app)) { | |
181 return false; | |
182 } | |
183 return true; | |
184 } | |
185 | |
186 void ArcAppPrefs::OnAppReady(const chromeos::ArcBridgeClient::AppInfo& app) { | |
187 std::string app_id = GetAppId(app.package, app.activity); | |
188 bool was_registered = IsRegistered(app_id); | |
189 | |
190 ScopedArcAppPrefUpdate update(prefs_, app_id); | |
191 base::DictionaryValue* app_dict = update.Get(); | |
192 app_dict->SetString(kName, app.name); | |
193 app_dict->SetString(kPackage, app.package); | |
194 app_dict->SetString(kActivity, app.activity); | |
195 | |
196 // From now, app is ready. | |
197 if (!enable_apps_.count(app_id)) { | |
198 enable_apps_.insert(app_id); | |
199 } | |
200 | |
201 AppInfo app_info; | |
202 app_info.name = app.name; | |
203 app_info.enabled = true; | |
204 | |
205 if (was_registered) { | |
206 FOR_EACH_OBSERVER(Observer, | |
207 observer_list_, | |
208 OnAppEnabled(app_id, true)); | |
209 } else { | |
210 FOR_EACH_OBSERVER(Observer, | |
211 observer_list_, | |
212 OnAppRegistered(app_id, app_info)); | |
213 } | |
214 | |
215 if (!app.icon.empty()) { | |
216 // Currently only default 100p icon is supported. | |
217 InstallIcon(app_id, ui::SCALE_FACTOR_100P, app.icon); | |
218 } | |
219 } | |
220 | |
221 void ArcAppPrefs::OnAppsRefreshed( | |
222 const std::vector<chromeos::ArcBridgeClient::AppInfo>& apps) { | |
223 std::set<std::string> old_enable_apps_; | |
224 old_enable_apps_.swap(enable_apps_); | |
225 | |
226 for (size_t i = 0; i < apps.size(); ++i) { | |
227 OnAppReady(apps[i]); | |
228 } | |
229 | |
230 // Detect unavailable apps after current refresh. | |
231 std::set<std::string>::const_iterator it; | |
232 for (it = old_enable_apps_.begin(); it != old_enable_apps_.end(); ++it) { | |
233 const std::string app_id = *it; | |
234 if (!enable_apps_.count(app_id)) { | |
235 FOR_EACH_OBSERVER(Observer, | |
236 observer_list_, | |
237 OnAppEnabled(app_id, false)); | |
238 } | |
239 } | |
240 } | |
241 | |
242 void ArcAppPrefs::InstallIcon(const std::string& app_id, | |
243 ui::ScaleFactor scale_factor, | |
244 const std::vector<uint8>& contentPng) { | |
245 base::Closure task = base::Bind(&ArcAppPrefs::InstallIconFromFileThread, | |
246 base::Unretained(this), | |
247 app_id, | |
248 scale_factor, | |
249 contentPng); | |
250 content::BrowserThread::PostTask(content::BrowserThread::FILE, | |
251 FROM_HERE, | |
252 task); | |
253 } | |
254 | |
255 void ArcAppPrefs::InstallIconFromFileThread( | |
256 const std::string& app_id, | |
257 ui::ScaleFactor scale_factor, | |
258 const std::vector<uint8>& contentPng) { | |
259 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | |
260 | |
261 DCHECK(!contentPng.empty()); | |
262 | |
263 IconInfo icon_info; | |
264 | |
265 base::FilePath app_path = base_path_.AppendASCII(app_id); | |
266 base::CreateDirectory(app_path); | |
267 icon_info.scale_factor = scale_factor; | |
268 icon_info.path = GetIconPath(app_path, scale_factor); | |
269 | |
270 int wrote = base::WriteFile(icon_info.path, | |
271 reinterpret_cast<const char*>(&contentPng[0]), | |
272 contentPng.size()); | |
273 DCHECK(wrote == static_cast<int>(contentPng.size())); | |
274 | |
275 base::Closure task = base::Bind(&ArcAppPrefs::OnIconInstalled, | |
276 base::Unretained(this), | |
277 app_id, | |
278 icon_info); | |
279 content::BrowserThread::PostTask(content::BrowserThread::UI, | |
280 FROM_HERE, | |
281 task); | |
282 } | |
283 | |
284 void ArcAppPrefs::OnIconInstalled(const std::string& app_id, | |
285 const IconInfo& icon_info) { | |
286 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
287 | |
288 FOR_EACH_OBSERVER(Observer, | |
289 observer_list_, | |
290 OnAppIconUpdated(app_id, icon_info)); | |
291 | |
292 // Set flag that icon is available for specific scale factor. | |
293 ScopedArcAppPrefUpdate update(prefs_, app_id); | |
294 base::DictionaryValue* app_dict = update.Get(); | |
295 int icon_flags = 0; | |
296 app_dict->GetInteger(kIcons, &icon_flags); | |
297 icon_flags |= (1 << icon_info.scale_factor); | |
298 app_dict->SetInteger(kIcons, icon_flags); | |
299 } | |
OLD | NEW |