| 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..557fe9141761e1a82e6d5909feb20605adf9f71e
|
| --- /dev/null
|
| +++ b/chrome/browser/ui/app_list/arc_app_prefs.cc
|
| @@ -0,0 +1,300 @@
|
| +// 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) {
|
| + 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);
|
| +}
|
| +
|
| +ArcAppPrefs::ArcAppPrefs(content::BrowserContext* browser_context,
|
| + const base::FilePath& base_path,
|
| + PrefService* prefs)
|
| + : browser_context_(browser_context),
|
| + prefs_(prefs) {
|
| + 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->ready = ready_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 (!ready_apps_.count(app_id)) {
|
| + ready_apps_.insert(app_id);
|
| + }
|
| +
|
| + if (was_registered) {
|
| + FOR_EACH_OBSERVER(Observer,
|
| + observer_list_,
|
| + OnAppReady(app_id, true));
|
| + } else {
|
| + AppInfo app_info;
|
| + app_info.name = app.name;
|
| + app_info.package = app.package;
|
| + app_info.activity = app.activity;
|
| + app_info.ready = true;
|
| + 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_ready_apps_;
|
| + old_ready_apps_.swap(ready_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_ready_apps_.begin(); it != old_ready_apps_.end(); ++it) {
|
| + const std::string app_id = *it;
|
| + if (!ready_apps_.count(app_id)) {
|
| + FOR_EACH_OBSERVER(Observer,
|
| + observer_list_,
|
| + OnAppReady(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);
|
| +}
|
|
|