Index: chrome/browser/ui/app_list/arc_app_prefs.cc |
diff --git a/chrome/browser/ui/app_list/arc_app_prefs.cc b/chrome/browser/ui/app_list/arc_app_prefs.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c1624cc7d69169ad905538381264ed9712aa1a2c |
--- /dev/null |
+++ b/chrome/browser/ui/app_list/arc_app_prefs.cc |
@@ -0,0 +1,299 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/ui/app_list/arc_app_prefs.h" |
+ |
+#include "base/files/file_util.h" |
+#include "base/prefs/scoped_user_pref_update.h" |
+#include "base/task_runner_util.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/ui/app_list/arc_app_prefs_factory.h" |
+#include "chromeos/dbus/dbus_thread_manager.h" |
+#include "components/crx_file/id_util.h" |
+#include "components/pref_registry/pref_registry_syncable.h" |
+#include "content/public/browser/browser_thread.h" |
+ |
+namespace { |
+ |
+const char kArcApps[] = "arcapps"; |
+const char kName[] = "name"; |
+const char kPackage[] = "package"; |
+const char kActivity[] = "activity"; |
+const char kIcons[] = "icons"; |
+ |
+// Provider of write access to a dictionary storing arc app prefs. |
+class ScopedArcAppPrefUpdate : public DictionaryPrefUpdate { |
+ public: |
+ ScopedArcAppPrefUpdate(PrefService* service, const std::string& id) |
+ : DictionaryPrefUpdate(service, kArcApps), |
+ id_(id) {} |
+ |
+ ~ScopedArcAppPrefUpdate() override {} |
+ |
+ // DictionaryPrefUpdate overrides: |
+ base::DictionaryValue* Get() override { |
+ base::DictionaryValue* dict = DictionaryPrefUpdate::Get(); |
+ base::DictionaryValue* app = NULL; |
+ if (!dict->GetDictionary(id_, &app)) { |
+ app = new base::DictionaryValue(); |
+ dict->SetWithoutPathExpansion(id_, app); |
+ } |
+ return app; |
+ } |
+ |
+ private: |
+ const std::string id_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ScopedArcAppPrefUpdate); |
+}; |
+ |
+base::FilePath GetIconPath(const base::FilePath& base_path, |
+ ui::ScaleFactor scale_factor) { |
+ 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
|
+ case ui::SCALE_FACTOR_100P: |
+ return base_path.AppendASCII("icon_100p.png"); |
+ case ui::SCALE_FACTOR_125P: |
+ return base_path.AppendASCII("icon_125p.png"); |
+ case ui::SCALE_FACTOR_133P: |
+ return base_path.AppendASCII("icon_133p.png"); |
+ case ui::SCALE_FACTOR_140P: |
+ return base_path.AppendASCII("icon_140p.png"); |
+ case ui::SCALE_FACTOR_150P: |
+ return base_path.AppendASCII("icon_150p.png"); |
+ case ui::SCALE_FACTOR_180P: |
+ return base_path.AppendASCII("icon_180p.png"); |
+ case ui::SCALE_FACTOR_200P: |
+ return base_path.AppendASCII("icon_200p.png"); |
+ case ui::SCALE_FACTOR_250P: |
+ return base_path.AppendASCII("icon_250p.png"); |
+ case ui::SCALE_FACTOR_300P: |
+ return base_path.AppendASCII("icon_300p.png"); |
+ default: |
+ CHECK(false); |
+ return base::FilePath(); |
+ } |
+} |
+ |
+} // namespace |
+ |
+// static |
+ArcAppPrefs* ArcAppPrefs::Create(content::BrowserContext* browser_context, |
+ const base::FilePath& base_path, |
+ PrefService* prefs) { |
+ return new ArcAppPrefs(browser_context, base_path, prefs); |
+} |
+ |
+// static |
+void ArcAppPrefs::RegisterProfilePrefs( |
+ user_prefs::PrefRegistrySyncable* registry) { |
+ registry->RegisterDictionaryPref( |
+ kArcApps, |
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
+} |
+ |
+// static |
+ArcAppPrefs* ArcAppPrefs::Get(content::BrowserContext* context) { |
+ return ArcAppPrefsFactory::GetInstance()->GetForBrowserContext(context); |
+} |
+ |
+// static |
+std::string ArcAppPrefs::GetAppId(const std::string& package, |
+ const std::string& activity) { |
+ std::string input = package + "#" + activity; |
+ 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
|
+} |
+ |
+ArcAppPrefs::ArcAppPrefs(content::BrowserContext* browser_context, |
+ const base::FilePath& base_path, |
+ PrefService* prefs) |
+ : browser_context_(browser_context), |
+ prefs_(prefs) { |
elijahtaylor1
2015/10/28 06:32:39
alignment
khmel1
2015/10/29 08:12:18
Done.
|
+ base_path_ = base_path.AppendASCII(kArcApps); |
+ |
+ chromeos::DBusThreadManager::Get()->GetArcBridgeClient()-> |
+ AddAppObserver(this); |
+ chromeos::DBusThreadManager::Get()->GetArcBridgeClient()->Refresh(); |
+} |
+ |
+ArcAppPrefs::~ArcAppPrefs() { |
+ chromeos::DBusThreadManager::Get()->GetArcBridgeClient()-> |
+ RemoveAppObserver(this); |
+} |
+ |
+void ArcAppPrefs::AddObserver(Observer* observer) { |
+ observer_list_.AddObserver(observer); |
+} |
+ |
+void ArcAppPrefs::RemoveObserver(Observer* observer) { |
+ observer_list_.RemoveObserver(observer); |
+} |
+ |
+std::vector<std::string> ArcAppPrefs::GetAppIds() const { |
+ std::vector<std::string> ids; |
+ |
+ const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps); |
+ for (base::DictionaryValue::Iterator app_id(*apps); |
+ !app_id.IsAtEnd(); app_id.Advance()) { |
+ if (!crx_file::id_util::IdIsValid(app_id.key())) |
+ continue; |
+ ids.push_back(app_id.key()); |
+ } |
+ |
+ return ids; |
+} |
+ |
+scoped_ptr<ArcAppPrefs::AppInfo> ArcAppPrefs::GetApp( |
+ const std::string& app_id) const { |
+ const base::DictionaryValue* app = NULL; |
+ const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps); |
+ if (!apps || |
+ !apps->GetDictionaryWithoutPathExpansion(app_id, &app)) |
+ return scoped_ptr<AppInfo>(); |
+ |
+ scoped_ptr<AppInfo> app_info(new AppInfo); |
+ app->GetString(kName, &app_info->name); |
+ app->GetString(kPackage, &app_info->package); |
+ app->GetString(kActivity, &app_info->activity); |
+ app_info->enabled = enable_apps_.count(app_id) > 0; |
+ |
+ base::FilePath app_path = base_path_.AppendASCII(app_id); |
+ |
+ int icon_flags = 0; |
+ if (app->GetInteger(kIcons, &icon_flags)) { |
+ for (int i = ui::SCALE_FACTOR_100P; i < ui::NUM_SCALE_FACTORS; ++i) { |
+ if (icon_flags & (1 << i)) { |
+ IconInfo icon_info; |
+ icon_info.scale_factor = static_cast<ui::ScaleFactor>(i); |
+ icon_info.path = GetIconPath(app_path, icon_info.scale_factor); |
+ app_info->icons.push_back(icon_info); |
+ } |
+ } |
+ } |
+ |
+ return app_info.Pass(); |
+} |
+ |
+bool ArcAppPrefs::IsRegistered(const std::string& app_id) { |
+ const base::DictionaryValue* app = NULL; |
+ const base::DictionaryValue* apps = prefs_->GetDictionary(kArcApps); |
+ if (!apps || !apps->GetDictionary(app_id, &app)) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+void ArcAppPrefs::OnAppReady(const chromeos::ArcBridgeClient::AppInfo& app) { |
+ std::string app_id = GetAppId(app.package, app.activity); |
+ bool was_registered = IsRegistered(app_id); |
+ |
+ ScopedArcAppPrefUpdate update(prefs_, app_id); |
+ base::DictionaryValue* app_dict = update.Get(); |
+ app_dict->SetString(kName, app.name); |
+ app_dict->SetString(kPackage, app.package); |
+ app_dict->SetString(kActivity, app.activity); |
+ |
+ // From now, app is ready. |
+ if (!enable_apps_.count(app_id)) { |
+ enable_apps_.insert(app_id); |
+ } |
+ |
+ AppInfo app_info; |
+ app_info.name = app.name; |
+ app_info.enabled = true; |
+ |
+ if (was_registered) { |
+ FOR_EACH_OBSERVER(Observer, |
+ observer_list_, |
+ OnAppEnabled(app_id, true)); |
+ } else { |
+ FOR_EACH_OBSERVER(Observer, |
+ observer_list_, |
+ OnAppRegistered(app_id, app_info)); |
+ } |
+ |
+ if (!app.icon.empty()) { |
+ // Currently only default 100p icon is supported. |
+ InstallIcon(app_id, ui::SCALE_FACTOR_100P, app.icon); |
+ } |
+} |
+ |
+void ArcAppPrefs::OnAppsRefreshed( |
+ const std::vector<chromeos::ArcBridgeClient::AppInfo>& apps) { |
+ std::set<std::string> old_enable_apps_; |
+ old_enable_apps_.swap(enable_apps_); |
+ |
+ for (size_t i = 0; i < apps.size(); ++i) { |
+ OnAppReady(apps[i]); |
+ } |
+ |
+ // Detect unavailable apps after current refresh. |
+ std::set<std::string>::const_iterator it; |
+ for (it = old_enable_apps_.begin(); it != old_enable_apps_.end(); ++it) { |
+ const std::string app_id = *it; |
+ if (!enable_apps_.count(app_id)) { |
+ FOR_EACH_OBSERVER(Observer, |
+ observer_list_, |
+ OnAppEnabled(app_id, false)); |
+ } |
+ } |
+} |
+ |
+void ArcAppPrefs::InstallIcon(const std::string& app_id, |
+ ui::ScaleFactor scale_factor, |
+ const std::vector<uint8>& contentPng) { |
+ base::Closure task = base::Bind(&ArcAppPrefs::InstallIconFromFileThread, |
+ base::Unretained(this), |
+ app_id, |
+ scale_factor, |
+ contentPng); |
+ content::BrowserThread::PostTask(content::BrowserThread::FILE, |
+ FROM_HERE, |
+ task); |
+} |
+ |
+void ArcAppPrefs::InstallIconFromFileThread( |
+ const std::string& app_id, |
+ ui::ScaleFactor scale_factor, |
+ const std::vector<uint8>& contentPng) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); |
+ |
+ DCHECK(!contentPng.empty()); |
+ |
+ IconInfo icon_info; |
+ |
+ base::FilePath app_path = base_path_.AppendASCII(app_id); |
+ base::CreateDirectory(app_path); |
+ icon_info.scale_factor = scale_factor; |
+ icon_info.path = GetIconPath(app_path, scale_factor); |
+ |
+ int wrote = base::WriteFile(icon_info.path, |
+ reinterpret_cast<const char*>(&contentPng[0]), |
+ contentPng.size()); |
+ DCHECK(wrote == static_cast<int>(contentPng.size())); |
+ |
+ base::Closure task = base::Bind(&ArcAppPrefs::OnIconInstalled, |
+ base::Unretained(this), |
+ app_id, |
+ icon_info); |
+ content::BrowserThread::PostTask(content::BrowserThread::UI, |
+ FROM_HERE, |
+ task); |
+} |
+ |
+void ArcAppPrefs::OnIconInstalled(const std::string& app_id, |
+ const IconInfo& icon_info) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ |
+ FOR_EACH_OBSERVER(Observer, |
+ observer_list_, |
+ OnAppIconUpdated(app_id, icon_info)); |
+ |
+ // Set flag that icon is available for specific scale factor. |
+ ScopedArcAppPrefUpdate update(prefs_, app_id); |
+ base::DictionaryValue* app_dict = update.Get(); |
+ int icon_flags = 0; |
+ app_dict->GetInteger(kIcons, &icon_flags); |
+ icon_flags |= (1 << icon_info.scale_factor); |
+ app_dict->SetInteger(kIcons, icon_flags); |
+} |