Chromium Code Reviews| 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 |