Commit 63cfe5b8 authored by Nigel Tao's avatar Nigel Tao Committed by Commit Bot

Reland "First draft of an App Service ARC++ publisher"

This is a reland of 7cd680d6

It is combined with the fix in http://crrev.com/c/1406488 "Fix switch on
apps::mojom::LaunchSource", which was not submitted, but has some
discussion of the build breakage.

Original change's description:
> First draft of an App Service ARC++ publisher
>
> Lots of TODOs, but there's enough implemented so that running "chrome
> --enable-features=AppService" will populate the launcher with ARC++
> apps' names and icons, and clicking on the icon will launch the app.
>
> BUG=826982
>
> Change-Id: Ie61b33ce9fa0588e53615f5e086d558fe6abf840
> Reviewed-on: https://chromium-review.googlesource.com/c/1377485
> Commit-Queue: Nigel Tao <nigeltao@chromium.org>
> Reviewed-by: Dominick Ng <dominickn@chromium.org>
> Reviewed-by: James Cook <jamescook@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#621923}

Bug: 826982
Change-Id: I76b5fdcc85f9992ad684c3eca57e0213050ef186
Reviewed-on: https://chromium-review.googlesource.com/c/1406490Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Commit-Queue: Nigel Tao <nigeltao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#622153}
parent 42b7e2ed
...@@ -3160,6 +3160,10 @@ jumbo_split_static_library("browser") { ...@@ -3160,6 +3160,10 @@ jumbo_split_static_library("browser") {
if (is_chromeos) { if (is_chromeos) {
sources += [ sources += [
"apps/app_service/arc_apps.cc",
"apps/app_service/arc_apps.h",
"apps/app_service/arc_apps_factory.cc",
"apps/app_service/arc_apps_factory.h",
"apps/app_service/built_in_chromeos_apps.cc", "apps/app_service/built_in_chromeos_apps.cc",
"apps/app_service/built_in_chromeos_apps.h", "apps/app_service/built_in_chromeos_apps.h",
"apps/app_service/extension_apps.cc", "apps/app_service/extension_apps.cc",
......
...@@ -41,6 +41,10 @@ AppServiceProxy::AppServiceProxy(Profile* profile) { ...@@ -41,6 +41,10 @@ AppServiceProxy::AppServiceProxy(Profile* profile) {
AppServiceProxy::~AppServiceProxy() = default; AppServiceProxy::~AppServiceProxy() = default;
apps::mojom::AppServicePtr& AppServiceProxy::AppService() {
return app_service_;
}
AppRegistryCache& AppServiceProxy::Cache() { AppRegistryCache& AppServiceProxy::Cache() {
return cache_; return cache_;
} }
......
...@@ -35,6 +35,7 @@ class AppServiceProxy : public KeyedService, public apps::mojom::Subscriber { ...@@ -35,6 +35,7 @@ class AppServiceProxy : public KeyedService, public apps::mojom::Subscriber {
~AppServiceProxy() override; ~AppServiceProxy() override;
apps::mojom::AppServicePtr& AppService();
AppRegistryCache& Cache(); AppRegistryCache& Cache();
void LoadIcon(const std::string& app_id, void LoadIcon(const std::string& app_id,
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#include "chrome/common/chrome_features.h" #include "chrome/common/chrome_features.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/content/browser_context_dependency_manager.h"
#if defined(OS_CHROMEOS)
#include "extensions/browser/extension_registry_factory.h"
#endif // OS_CHROMEOS
namespace apps { namespace apps {
// static // static
...@@ -39,7 +43,11 @@ bool AppServiceProxyFactory::IsEnabled() { ...@@ -39,7 +43,11 @@ bool AppServiceProxyFactory::IsEnabled() {
AppServiceProxyFactory::AppServiceProxyFactory() AppServiceProxyFactory::AppServiceProxyFactory()
: BrowserContextKeyedServiceFactory( : BrowserContextKeyedServiceFactory(
"AppServiceProxy", "AppServiceProxy",
BrowserContextDependencyManager::GetInstance()) {} BrowserContextDependencyManager::GetInstance()) {
#if defined(OS_CHROMEOS)
DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
#endif // OS_CHROMEOS
}
AppServiceProxyFactory::~AppServiceProxyFactory() = default; AppServiceProxyFactory::~AppServiceProxyFactory() = default;
......
// Copyright 2018 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/apps/app_service/arc_apps.h"
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/arc_apps_factory.h"
#include "chrome/browser/apps/app_service/dip_px_util.h"
#include "chrome/browser/chromeos/arc/arc_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service_manager.h"
#include "content/public/common/service_manager_connection.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/data_decoder/public/cpp/decode_image.h"
#include "ui/gfx/geometry/size.h"
namespace {
// ArcApps::LoadIcon runs a series of callbacks, defined here in back-to-front
// order so that e.g. the compiler knows LoadIcon2's signature when compiling
// LoadIcon1 (which binds LoadIcon2).
//
// - LoadIcon0 is called back when the AppConnectionHolder is connected.
// - LoadIcon1 is called back when the compressed (PNG) image is loaded.
// - LoadIcon2 is called back when the uncompressed image is loaded.
void LoadIcon2(apps::mojom::Publisher::LoadIconCallback callback,
const SkBitmap& bitmap) {
apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New();
iv->icon_compression = apps::mojom::IconCompression::kUncompressed;
iv->uncompressed = gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, 0.0f));
std::move(callback).Run(std::move(iv));
}
void LoadIcon1(apps::mojom::IconCompression icon_compression,
apps::mojom::Publisher::LoadIconCallback callback,
const std::vector<uint8_t>& icon_png_data) {
switch (icon_compression) {
case apps::mojom::IconCompression::kUnknown:
std::move(callback).Run(apps::mojom::IconValue::New());
break;
case apps::mojom::IconCompression::kUncompressed:
data_decoder::DecodeImage(
content::ServiceManagerConnection::GetForProcess()->GetConnector(),
icon_png_data, data_decoder::mojom::ImageCodec::DEFAULT, false,
data_decoder::kDefaultMaxSizeInBytes, gfx::Size(),
base::BindOnce(&LoadIcon2, std::move(callback)));
break;
case apps::mojom::IconCompression::kCompressed:
apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New();
iv->icon_compression = apps::mojom::IconCompression::kCompressed;
iv->compressed = icon_png_data;
std::move(callback).Run(std::move(iv));
break;
}
}
void LoadIcon0(apps::mojom::IconCompression icon_compression,
int size_hint_in_px,
std::string package_name,
std::string activity,
std::string icon_resource_id,
apps::mojom::Publisher::LoadIconCallback callback,
apps::ArcApps::AppConnectionHolder* app_connection_holder) {
if (icon_resource_id.empty()) {
auto* app_instance =
ARC_GET_INSTANCE_FOR_METHOD(app_connection_holder, RequestAppIcon);
if (app_instance) {
app_instance->RequestAppIcon(
package_name, activity, size_hint_in_px,
base::BindOnce(&LoadIcon1, icon_compression, std::move(callback)));
return;
}
} else {
auto* app_instance =
ARC_GET_INSTANCE_FOR_METHOD(app_connection_holder, RequestShortcutIcon);
if (app_instance) {
app_instance->RequestShortcutIcon(
icon_resource_id, size_hint_in_px,
base::BindOnce(&LoadIcon1, icon_compression, std::move(callback)));
return;
}
}
// On failure, we still run the callback, with the zero IconValue.
std::move(callback).Run(apps::mojom::IconValue::New());
}
} // namespace
namespace apps {
// static
ArcApps* ArcApps::Get(Profile* profile) {
return ArcAppsFactory::GetForProfile(profile);
}
ArcApps::ArcApps(Profile* profile)
: binding_(this),
profile_(profile),
prefs_(ArcAppListPrefs::Get(profile)),
next_u_key_(1) {
if (!prefs_ || !arc::IsArcAllowedForProfile(profile_)) {
return;
}
auto* arc_service_manager = arc::ArcServiceManager::Get();
if (!arc_service_manager) {
return;
}
ObservePrefs();
apps::mojom::PublisherPtr publisher;
binding_.Bind(mojo::MakeRequest(&publisher));
apps::AppServiceProxy::Get(profile)->AppService()->RegisterPublisher(
std::move(publisher), apps::mojom::AppType::kArc);
}
ArcApps::~ArcApps() {
if (prefs_) {
prefs_->app_connection_holder()->RemoveObserver(this);
prefs_->RemoveObserver(this);
}
}
void ArcApps::Connect(apps::mojom::SubscriberPtr subscriber,
apps::mojom::ConnectOptionsPtr opts) {
std::vector<apps::mojom::AppPtr> apps;
if (prefs_) {
for (const auto& app_id : prefs_->GetAppIds()) {
std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
prefs_->GetApp(app_id);
if (app_info) {
apps.push_back(Convert(app_id, *app_info));
}
}
}
subscriber->OnApps(std::move(apps));
subscribers_.AddPtr(std::move(subscriber));
}
void ArcApps::LoadIcon(const std::string& app_id,
apps::mojom::IconKeyPtr icon_key,
apps::mojom::IconCompression icon_compression,
int32_t size_hint_in_dip,
LoadIconCallback callback) {
if (prefs_ && !icon_key.is_null() &&
(icon_key->icon_type == apps::mojom::IconType::kArc) &&
!icon_key->s_key.empty()) {
std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
prefs_->GetApp(icon_key->s_key);
if (app_info) {
base::OnceCallback<void(apps::ArcApps::AppConnectionHolder*)> pending =
base::BindOnce(&LoadIcon0, icon_compression,
ConvertDipToPx(size_hint_in_dip),
app_info->package_name, app_info->activity,
app_info->icon_resource_id, std::move(callback));
AppConnectionHolder* app_connection_holder =
prefs_->app_connection_holder();
if (app_connection_holder->IsConnected()) {
std::move(pending).Run(app_connection_holder);
} else {
pending_load_icon_calls_.push_back(std::move(pending));
}
return;
}
}
// On failure, we still run the callback, with the zero IconValue.
std::move(callback).Run(apps::mojom::IconValue::New());
}
void ArcApps::Launch(const std::string& app_id,
int32_t event_flags,
apps::mojom::LaunchSource launch_source,
int64_t display_id) {
auto uit = arc::UserInteractionType::NOT_USER_INITIATED;
switch (launch_source) {
case apps::mojom::LaunchSource::kUnknown:
return;
case apps::mojom::LaunchSource::kFromAppListGrid:
uit = arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER;
break;
case apps::mojom::LaunchSource::kFromAppListGridContextMenu:
uit = arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER_CONTEXT_MENU;
break;
case apps::mojom::LaunchSource::kFromAppListQuery:
uit = arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER_SEARCH;
break;
case apps::mojom::LaunchSource::kFromAppListQueryContextMenu:
uit = arc::UserInteractionType::
APP_STARTED_FROM_LAUNCHER_SEARCH_CONTEXT_MENU;
break;
case apps::mojom::LaunchSource::kFromAppListRecommendation:
uit = arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER_SUGGESTED_APP;
break;
}
arc::LaunchApp(profile_, app_id, event_flags, uit, display_id);
}
void ArcApps::SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission) {
NOTIMPLEMENTED();
}
void ArcApps::OnConnectionReady() {
if (!prefs_) {
prefs_ = ArcAppListPrefs::Get(profile_);
ObservePrefs();
}
if (prefs_) {
AppConnectionHolder* app_connection_holder =
prefs_->app_connection_holder();
for (auto& pending : pending_load_icon_calls_) {
std::move(pending).Run(app_connection_holder);
}
pending_load_icon_calls_.clear();
}
}
void ArcApps::ObservePrefs() {
prefs_->AddObserver(this);
prefs_->app_connection_holder()->AddObserver(this);
}
apps::mojom::AppPtr ArcApps::Convert(const std::string& app_id,
const ArcAppListPrefs::AppInfo& app_info) {
apps::mojom::AppPtr app = apps::mojom::App::New();
app->app_type = apps::mojom::AppType::kArc;
app->app_id = app_id;
app->readiness = apps::mojom::Readiness::kReady;
app->name = app_info.name;
app->icon_key = apps::mojom::IconKey::New();
app->icon_key->icon_type = apps::mojom::IconType::kArc;
app->icon_key->s_key = app_id;
app->icon_key->u_key = next_u_key_++;
auto show = app_info.show_in_launcher ? apps::mojom::OptionalBool::kTrue
: apps::mojom::OptionalBool::kFalse;
app->show_in_launcher = show;
app->show_in_search = show;
return app;
}
} // namespace apps
// Copyright 2018 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.
#ifndef CHROME_BROWSER_APPS_APP_SERVICE_ARC_APPS_H_
#define CHROME_BROWSER_APPS_APP_SERVICE_ARC_APPS_H_
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
#include "chrome/services/app_service/public/mojom/app_service.mojom.h"
#include "components/arc/connection_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
class Profile;
namespace apps {
// An app publisher (in the App Service sense) of ARC++ apps,
//
// See chrome/services/app_service/README.md.
class ArcApps : public KeyedService,
public apps::mojom::Publisher,
public arc::ConnectionObserver<arc::mojom::AppInstance>,
public ArcAppListPrefs::Observer {
public:
using AppConnectionHolder =
arc::ConnectionHolder<arc::mojom::AppInstance, arc::mojom::AppHost>;
static ArcApps* Get(Profile* profile);
explicit ArcApps(Profile* profile);
~ArcApps() override;
private:
// apps::mojom::Publisher overrides.
void Connect(apps::mojom::SubscriberPtr subscriber,
apps::mojom::ConnectOptionsPtr opts) override;
void LoadIcon(const std::string& app_id,
apps::mojom::IconKeyPtr icon_key,
apps::mojom::IconCompression icon_compression,
int32_t size_hint_in_dip,
LoadIconCallback callback) override;
void Launch(const std::string& app_id,
int32_t event_flags,
apps::mojom::LaunchSource launch_source,
int64_t display_id) override;
void SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission) override;
// arc::ConnectionObserver<arc::mojom::AppInstance> overrides.
void OnConnectionReady() override;
// ArcAppListPrefs::Observer overrides.
// TODO(crbug.com/826982): implement.
void ObservePrefs();
apps::mojom::AppPtr Convert(const std::string& app_id,
const ArcAppListPrefs::AppInfo& app_info);
mojo::Binding<apps::mojom::Publisher> binding_;
mojo::InterfacePtrSet<apps::mojom::Subscriber> subscribers_;
Profile* profile_;
ArcAppListPrefs* prefs_;
std::vector<base::OnceCallback<void(AppConnectionHolder*)>>
pending_load_icon_calls_;
// |next_u_key_| is incremented every time Convert returns a valid AppPtr, so
// that when an app's icon has changed, this apps::mojom::Publisher sends a
// different IconKey even though the IconKey's s_key hasn't changed.
uint64_t next_u_key_;
DISALLOW_COPY_AND_ASSIGN(ArcApps);
};
} // namespace apps
#endif // CHROME_BROWSER_APPS_APP_SERVICE_ARC_APPS_H_
// Copyright 2018 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/apps/app_service/arc_apps_factory.h"
#include "base/feature_list.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/arc_apps.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
#include "chrome/common/chrome_features.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
namespace apps {
// static
ArcApps* ArcAppsFactory::GetForProfile(Profile* profile) {
return static_cast<ArcApps*>(
ArcAppsFactory::GetInstance()->GetServiceForBrowserContext(
profile, true /* create */));
}
// static
ArcAppsFactory* ArcAppsFactory::GetInstance() {
return base::Singleton<ArcAppsFactory>::get();
}
// static
bool ArcAppsFactory::IsEnabled() {
return base::FeatureList::IsEnabled(features::kAppService);
}
ArcAppsFactory::ArcAppsFactory()
: BrowserContextKeyedServiceFactory(
"ArcApps",
BrowserContextDependencyManager::GetInstance()) {
DependsOn(ArcAppListPrefsFactory::GetInstance());
DependsOn(apps::AppServiceProxyFactory::GetInstance());
}
ArcAppsFactory::~ArcAppsFactory() = default;
KeyedService* ArcAppsFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new ArcApps(Profile::FromBrowserContext(context));
}
} // namespace apps
// Copyright 2018 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.
#ifndef CHROME_BROWSER_APPS_APP_SERVICE_ARC_APPS_FACTORY_H_
#define CHROME_BROWSER_APPS_APP_SERVICE_ARC_APPS_FACTORY_H_
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
class Profile;
namespace apps {
class ArcApps;
class ArcAppsFactory : public BrowserContextKeyedServiceFactory {
public:
static ArcApps* GetForProfile(Profile* profile);
static ArcAppsFactory* GetInstance();
static bool IsEnabled();
private:
friend struct base::DefaultSingletonTraits<ArcAppsFactory>;
ArcAppsFactory();
~ArcAppsFactory() override;
// BrowserContextKeyedServiceFactory overrides.
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
DISALLOW_COPY_AND_ASSIGN(ArcAppsFactory);
};
} // namespace apps
#endif // CHROME_BROWSER_APPS_APP_SERVICE_ARC_APPS_FACTORY_H_
...@@ -41,6 +41,7 @@ class BuiltInChromeOsApps : public apps::mojom::Publisher { ...@@ -41,6 +41,7 @@ class BuiltInChromeOsApps : public apps::mojom::Publisher {
apps::mojom::PermissionPtr permission) override; apps::mojom::PermissionPtr permission) override;
mojo::Binding<apps::mojom::Publisher> binding_; mojo::Binding<apps::mojom::Publisher> binding_;
Profile* profile_; Profile* profile_;
DISALLOW_COPY_AND_ASSIGN(BuiltInChromeOsApps); DISALLOW_COPY_AND_ASSIGN(BuiltInChromeOsApps);
......
...@@ -67,12 +67,13 @@ class ExtensionApps : public apps::mojom::Publisher, ...@@ -67,12 +67,13 @@ class ExtensionApps : public apps::mojom::Publisher,
std::vector<apps::mojom::AppPtr>* apps_out); std::vector<apps::mojom::AppPtr>* apps_out);
mojo::Binding<apps::mojom::Publisher> binding_; mojo::Binding<apps::mojom::Publisher> binding_;
Profile* profile_;
mojo::InterfacePtrSet<apps::mojom::Subscriber> subscribers_; mojo::InterfacePtrSet<apps::mojom::Subscriber> subscribers_;
Profile* profile_;
// |next_u_key_| is incremented every time Convert returns a valid AppPtr, so // |next_u_key_| is incremented every time Convert returns a valid AppPtr, so
// that when an extension's icon has changed, this apps::mojom::Publisher // that when an app's icon has changed, this apps::mojom::Publisher sends a
// sends a different IconKey even though the IconKey's s_key hasn't changed. // different IconKey even though the IconKey's s_key hasn't changed.
uint64_t next_u_key_; uint64_t next_u_key_;
ScopedObserver<extensions::ExtensionRegistry, ScopedObserver<extensions::ExtensionRegistry,
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ash/public/interfaces/constants.mojom.h" #include "ash/public/interfaces/constants.mojom.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
#include "chrome/browser/apps/app_service/arc_apps_factory.h"
#include "chrome/browser/chromeos/apps/apk_web_app_service.h" #include "chrome/browser/chromeos/apps/apk_web_app_service.h"
#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h" #include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
#include "chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.h" #include "chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.h"
...@@ -200,6 +201,9 @@ void ArcServiceLauncher::OnPrimaryUserProfilePrepared(Profile* profile) { ...@@ -200,6 +201,9 @@ void ArcServiceLauncher::OnPrimaryUserProfilePrepared(Profile* profile) {
ArcWakeLockBridge::GetForBrowserContext(profile); ArcWakeLockBridge::GetForBrowserContext(profile);
ArcWallpaperService::GetForBrowserContext(profile); ArcWallpaperService::GetForBrowserContext(profile);
GpuArcVideoServiceHost::GetForBrowserContext(profile); GpuArcVideoServiceHost::GetForBrowserContext(profile);
if (apps::ArcAppsFactory::IsEnabled()) {
apps::ArcAppsFactory::GetForProfile(profile);
}
chromeos::ApkWebAppService::Get(profile); chromeos::ApkWebAppService::Get(profile);
arc_session_manager_->Initialize(); arc_session_manager_->Initialize();
......
...@@ -72,6 +72,7 @@ enum OptionalBool { ...@@ -72,6 +72,7 @@ enum OptionalBool {
enum IconType { enum IconType {
kUnknown, kUnknown,
kArc,
kExtension, kExtension,
kResource, kResource,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment