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) { |
| 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); |
| 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) { |
| 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->ready = ready_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 (!ready_apps_.count(app_id)) { |
| 198 ready_apps_.insert(app_id); |
| 199 } |
| 200 |
| 201 if (was_registered) { |
| 202 FOR_EACH_OBSERVER(Observer, |
| 203 observer_list_, |
| 204 OnAppReady(app_id, true)); |
| 205 } else { |
| 206 AppInfo app_info; |
| 207 app_info.name = app.name; |
| 208 app_info.package = app.package; |
| 209 app_info.activity = app.activity; |
| 210 app_info.ready = true; |
| 211 FOR_EACH_OBSERVER(Observer, |
| 212 observer_list_, |
| 213 OnAppRegistered(app_id, app_info)); |
| 214 } |
| 215 |
| 216 if (!app.icon.empty()) { |
| 217 // Currently only default 100p icon is supported. |
| 218 InstallIcon(app_id, ui::SCALE_FACTOR_100P, app.icon); |
| 219 } |
| 220 } |
| 221 |
| 222 void ArcAppPrefs::OnAppsRefreshed( |
| 223 const std::vector<chromeos::ArcBridgeClient::AppInfo>& apps) { |
| 224 std::set<std::string> old_ready_apps_; |
| 225 old_ready_apps_.swap(ready_apps_); |
| 226 |
| 227 for (size_t i = 0; i < apps.size(); ++i) { |
| 228 OnAppReady(apps[i]); |
| 229 } |
| 230 |
| 231 // Detect unavailable apps after current refresh. |
| 232 std::set<std::string>::const_iterator it; |
| 233 for (it = old_ready_apps_.begin(); it != old_ready_apps_.end(); ++it) { |
| 234 const std::string app_id = *it; |
| 235 if (!ready_apps_.count(app_id)) { |
| 236 FOR_EACH_OBSERVER(Observer, |
| 237 observer_list_, |
| 238 OnAppReady(app_id, false)); |
| 239 } |
| 240 } |
| 241 } |
| 242 |
| 243 void ArcAppPrefs::InstallIcon(const std::string& app_id, |
| 244 ui::ScaleFactor scale_factor, |
| 245 const std::vector<uint8>& contentPng) { |
| 246 base::Closure task = base::Bind(&ArcAppPrefs::InstallIconFromFileThread, |
| 247 base::Unretained(this), |
| 248 app_id, |
| 249 scale_factor, |
| 250 contentPng); |
| 251 content::BrowserThread::PostTask(content::BrowserThread::FILE, |
| 252 FROM_HERE, |
| 253 task); |
| 254 } |
| 255 |
| 256 void ArcAppPrefs::InstallIconFromFileThread( |
| 257 const std::string& app_id, |
| 258 ui::ScaleFactor scale_factor, |
| 259 const std::vector<uint8>& contentPng) { |
| 260 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); |
| 261 |
| 262 DCHECK(!contentPng.empty()); |
| 263 |
| 264 IconInfo icon_info; |
| 265 |
| 266 base::FilePath app_path = base_path_.AppendASCII(app_id); |
| 267 base::CreateDirectory(app_path); |
| 268 icon_info.scale_factor = scale_factor; |
| 269 icon_info.path = GetIconPath(app_path, scale_factor); |
| 270 |
| 271 int wrote = base::WriteFile(icon_info.path, |
| 272 reinterpret_cast<const char*>(&contentPng[0]), |
| 273 contentPng.size()); |
| 274 DCHECK(wrote == static_cast<int>(contentPng.size())); |
| 275 |
| 276 base::Closure task = base::Bind(&ArcAppPrefs::OnIconInstalled, |
| 277 base::Unretained(this), |
| 278 app_id, |
| 279 icon_info); |
| 280 content::BrowserThread::PostTask(content::BrowserThread::UI, |
| 281 FROM_HERE, |
| 282 task); |
| 283 } |
| 284 |
| 285 void ArcAppPrefs::OnIconInstalled(const std::string& app_id, |
| 286 const IconInfo& icon_info) { |
| 287 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 288 |
| 289 FOR_EACH_OBSERVER(Observer, |
| 290 observer_list_, |
| 291 OnAppIconUpdated(app_id, icon_info)); |
| 292 |
| 293 // Set flag that icon is available for specific scale factor. |
| 294 ScopedArcAppPrefUpdate update(prefs_, app_id); |
| 295 base::DictionaryValue* app_dict = update.Get(); |
| 296 int icon_flags = 0; |
| 297 app_dict->GetInteger(kIcons, &icon_flags); |
| 298 icon_flags |= (1 << icon_info.scale_factor); |
| 299 app_dict->SetInteger(kIcons, icon_flags); |
| 300 } |
OLD | NEW |