Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8097)

Unified Diff: chrome/browser/ui/app_list/arc_app_list_prefs.cc

Issue 1413153007: arc-app-launcher: Minimal support for ARC app launcher. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: revert wrongly update chrome/chrome_browser_ui.gypi Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/app_list/arc_app_list_prefs.cc
diff --git a/chrome/browser/ui/app_list/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc_app_list_prefs.cc
new file mode 100644
index 0000000000000000000000000000000000000000..58193dfbdc39f55fb452ef206a33f6d87e00b79f
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc_app_list_prefs.cc
@@ -0,0 +1,373 @@
+// 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_list_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_list_prefs_factory.h"
+#include "chrome/common/pref_names.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 kName[] = "name";
+const char kPackage[] = "package";
+const char kActivity[] = "activity";
+
+// Provider of write access to a dictionary storing ARC app prefs.
+class ScopedArcAppListPrefUpdate : public DictionaryPrefUpdate {
+ public:
+ ScopedArcAppListPrefUpdate(PrefService* service, const std::string& id)
+ : DictionaryPrefUpdate(service, prefs::kArcApps),
+ id_(id) {}
+
+ ~ScopedArcAppListPrefUpdate() override {}
+
+ // DictionaryPrefUpdate overrides:
+ base::DictionaryValue* Get() override {
+ base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
+ base::DictionaryValue* app = NULL;
xiyuan 2015/11/13 17:14:22 nit: NULL -> nullptr
khmel1 2015/11/17 13:18:02 Done.
+ if (!dict->GetDictionary(id_, &app)) {
+ app = new base::DictionaryValue();
+ dict->SetWithoutPathExpansion(id_, app);
+ }
+ return app;
+ }
+
+ private:
+ const std::string id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedArcAppListPrefUpdate);
+};
+
+} // namespace
+
+// static
+ArcAppListPrefs* ArcAppListPrefs::Create(const base::FilePath& base_path,
+ PrefService* prefs) {
+ return new ArcAppListPrefs(base_path, prefs);
+}
+
+// static
+void ArcAppListPrefs::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterDictionaryPref(
+ prefs::kArcApps,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+}
+
+// static
+ArcAppListPrefs* ArcAppListPrefs::Get(content::BrowserContext* context) {
+ return ArcAppListPrefsFactory::GetInstance()->GetForBrowserContext(context);
+}
+
+// static
+std::string ArcAppListPrefs::GetAppId(const std::string& package,
+ const std::string& activity) {
+ std::string input = package + "#" + activity;
+ return crx_file::id_util::GenerateId(input);
+}
+
+ArcAppListPrefs::ArcAppListPrefs(const base::FilePath& base_path,
+ PrefService* prefs)
+ : prefs_(prefs),
+ weak_ptr_factory_(this) {
+ base_path_ = base_path.AppendASCII(prefs::kArcApps);
+
+ arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
+ if (!bridge_service) {
+ LOG(ERROR) << "Bridge service is not available. Cannot init.";
+ return;
+ }
+
+ bridge_service->AddObserver(this);
+ OnStateChanged(bridge_service->state());
+}
+
+ArcAppListPrefs::~ArcAppListPrefs() {
+ arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
+ if (bridge_service) {
+ bridge_service->RemoveObserver(this);
+ }
+}
+
+base::FilePath ArcAppListPrefs::GetIconPath(
+ const std::string& app_id,
+ ui::ScaleFactor scale_factor) const {
+ base::FilePath app_path = base_path_.AppendASCII(app_id);
+ switch (scale_factor) {
+ case ui::SCALE_FACTOR_100P:
+ return app_path.AppendASCII("icon_100p.png");
+ case ui::SCALE_FACTOR_125P:
+ return app_path.AppendASCII("icon_125p.png");
+ case ui::SCALE_FACTOR_133P:
+ return app_path.AppendASCII("icon_133p.png");
+ case ui::SCALE_FACTOR_140P:
+ return app_path.AppendASCII("icon_140p.png");
+ case ui::SCALE_FACTOR_150P:
+ return app_path.AppendASCII("icon_150p.png");
+ case ui::SCALE_FACTOR_180P:
+ return app_path.AppendASCII("icon_180p.png");
+ case ui::SCALE_FACTOR_200P:
+ return app_path.AppendASCII("icon_200p.png");
+ case ui::SCALE_FACTOR_250P:
+ return app_path.AppendASCII("icon_250p.png");
+ case ui::SCALE_FACTOR_300P:
+ return app_path.AppendASCII("icon_300p.png");
+ default:
+ NOTREACHED();
+ return base::FilePath();
+ }
+}
+
+void ArcAppListPrefs::RequestIcon(const std::string& app_id,
+ ui::ScaleFactor scale_factor) {
+ if (!IsRegistered(app_id)) {
+ LOG(ERROR) << "Request to load icon for non-registered app: "
+ << app_id << ".";
+ return;
+ }
+
+ // In case app is not ready, defer this request.
+ if (!ready_apps_.count(app_id)) {
+ request_icon_deferred_[app_id] =
+ request_icon_deferred_[app_id] | 1 << scale_factor;
+ return;
+ }
+
+ arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
+ if (!bridge_service ||
+ bridge_service->state() != arc::ArcBridgeService::State::READY) {
+ LOG(ERROR) << "Request to load icon when bridge service is not ready: "
+ << app_id << ".";
+ return;
+ }
+
+ scoped_ptr<AppInfo> app_info = GetApp(app_id);
+ if (!app_info) {
+ LOG(ERROR) << "Failed to get app info: " << app_id << ".";
+ return;
+ }
+
+ bridge_service->RequestIcon(app_info->package,
+ app_info->activity,
+ static_cast<int>(scale_factor));
+}
+
+void ArcAppListPrefs::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void ArcAppListPrefs::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+std::vector<std::string> ArcAppListPrefs::GetAppIds() const {
+ std::vector<std::string> ids;
+
+ // crx_file::id_util is de-factor utility for id generation.
+ const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::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<ArcAppListPrefs::AppInfo> ArcAppListPrefs::GetApp(
+ const std::string& app_id) const {
+ const base::DictionaryValue* app = NULL;
xiyuan 2015/11/13 17:14:22 nit: NULL -> nullptr
khmel1 2015/11/17 13:18:02 Done.
+ const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::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;
+
+ return app_info.Pass();
+}
+
+bool ArcAppListPrefs::IsRegistered(const std::string& app_id) {
+ const base::DictionaryValue* app = NULL;
xiyuan 2015/11/13 17:14:22 nit: NULL -> nullptr
khmel1 2015/11/17 13:18:02 Done.
+ const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+ if (!apps || !apps->GetDictionary(app_id, &app)) {
+ return false;
+ }
+ return true;
+}
+
+void ArcAppListPrefs::DisableAllApps() {
+ for (auto& app_id : ready_apps_) {
+ FOR_EACH_OBSERVER(Observer,
+ observer_list_,
+ OnAppReadyChanged(app_id, false));
+ }
+ ready_apps_.clear();
+}
+
+void ArcAppListPrefs::OnStateChanged(arc::ArcBridgeService::State state) {
+ if (state == arc::ArcBridgeService::State::READY) {
+ arc::ArcBridgeService::Get()->RefreshApps();
+ } else {
+ DisableAllApps();
+ }
+}
+
+void ArcAppListPrefs::OnAppReady(const std::string& name,
+ const std::string& package,
+ const std::string& activity) {
+ if (name.empty() || package.empty() || activity.empty()) {
+ LOG(ERROR) << "Name, package and activity cannot be empty.";
+ return;
+ }
+ std::string app_id = GetAppId(package, activity);
+ bool was_registered = IsRegistered(app_id);
+
+ ScopedArcAppListPrefUpdate update(prefs_, app_id);
+ base::DictionaryValue* app_dict = update.Get();
+ app_dict->SetString(kName, name);
+ app_dict->SetString(kPackage, package);
+ app_dict->SetString(kActivity, 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_,
+ OnAppReadyChanged(app_id, true));
+ } else {
+ AppInfo app_info;
+ app_info.name = name;
+ app_info.package = package;
+ app_info.activity = activity;
+ app_info.ready = true;
+ FOR_EACH_OBSERVER(Observer,
+ observer_list_,
+ OnAppRegistered(app_id, app_info));
+ }
+
+ std::map<std::string, uint32>::iterator deferred_icons =
+ request_icon_deferred_.find(app_id);
+ if (deferred_icons != request_icon_deferred_.end()) {
+ for (uint32 i = ui::SCALE_FACTOR_100P; i < ui::NUM_SCALE_FACTORS; ++i) {
+ if (deferred_icons->second & (1 << i)) {
+ RequestIcon(app_id, static_cast<ui::ScaleFactor>(i));
+ }
+ }
+ request_icon_deferred_.erase(deferred_icons);
+ }
+}
+
+void ArcAppListPrefs::OnAppsRefreshed(
+ const std::vector<std::string>& names,
+ const std::vector<std::string>& packages,
+ const std::vector<std::string>& activities) {
+ if (names.size() != packages.size() || names.size() != activities.size()) {
+ LOG(ERROR) << "Name, package and activity must be the same size.";
+ return;
+ }
+
+ std::set<std::string> old_ready_apps;
+ old_ready_apps.swap(ready_apps_);
+
+ for (size_t i = 0; i < names.size(); ++i) {
+ OnAppReady(names[i], packages[i], activities[i]);
+ }
+
+ // Detect unavailable apps after current refresh.
+ for (auto& app_id : old_ready_apps) {
+ if (!ready_apps_.count(app_id)) {
+ FOR_EACH_OBSERVER(Observer,
+ observer_list_,
+ OnAppReadyChanged(app_id, false));
+ }
+ }
+}
+
+void ArcAppListPrefs::OnAppIcon(const std::string& package,
+ const std::string& activity,
+ int scale_factor,
+ const std::vector<uint8_t>& icon_png_data) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(!icon_png_data.empty());
+ DCHECK(scale_factor >= ui::SCALE_FACTOR_100P &&
+ scale_factor < ui::NUM_SCALE_FACTORS);
+
+ std::string app_id = GetAppId(package, activity);
+ if (!IsRegistered(app_id)) {
+ LOG(ERROR) << "Request to update icon for non-registered app: " << app_id;
+ return;
+ }
+
+ InstallIcon(app_id,
+ static_cast<ui::ScaleFactor>(scale_factor),
+ icon_png_data);
+}
+
+
+void ArcAppListPrefs::InstallIcon(const std::string& app_id,
+ ui::ScaleFactor scale_factor,
+ const std::vector<uint8>& content_png) {
+ base::Closure task = base::Bind(&ArcAppListPrefs::InstallIconFromFileThread,
+ weak_ptr_factory_.GetWeakPtr(),
+ app_id,
+ scale_factor,
+ content_png);
+ content::BrowserThread::GetBlockingPool()->PostTask(FROM_HERE, task);
+}
+
+void ArcAppListPrefs::InstallIconFromFileThread(
+ const std::string& app_id,
+ ui::ScaleFactor scale_factor,
+ const std::vector<uint8>& content_png) {
+ DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+ DCHECK(!content_png.empty());
+
+ base::FilePath app_path = base_path_.AppendASCII(app_id);
+ base::CreateDirectory(app_path);
+ base::FilePath icon_path = GetIconPath(app_id, scale_factor);
+
+ int wrote = base::WriteFile(icon_path,
+ reinterpret_cast<const char*>(&content_png[0]),
+ content_png.size());
+ if (wrote != static_cast<int>(content_png.size())) {
+ LOG(ERROR) << "Failed to write ARC icon file: " << icon_path.MaybeAsASCII()
+ << ".";
+ DCHECK(base::DeleteFile(icon_path, false));
+ return;
+ }
+
+ base::Closure task = base::Bind(&ArcAppListPrefs::OnIconInstalled,
+ weak_ptr_factory_.GetWeakPtr(),
+ app_id,
+ scale_factor);
+ content::BrowserThread::PostTask(content::BrowserThread::UI,
+ FROM_HERE,
+ task);
+}
+
+void ArcAppListPrefs::OnIconInstalled(const std::string& app_id,
+ ui::ScaleFactor scale_factor) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ FOR_EACH_OBSERVER(Observer,
+ observer_list_,
+ OnAppIconUpdated(app_id, scale_factor));
+}

Powered by Google App Engine
This is Rietveld 408576698