Commit 444e86be authored by nancylingwang's avatar nancylingwang Committed by Commit Bot

Modify intent to support the adaptive icon

Add the interface ArcActivityIconsToImageSkias in app_icon_factory.cc to
load a group of icons for the ARC activity.

Add ArcActivityAdaptiveIconImpl to generate the adaptive icons for the
ARC activity by calling ArcActivityIconsToImageSkias. Modify ArcApps to
set the ArcActivityAdaptiveIconImpl as the delegate for the
ActivityIconLoader if the adaptive icon is enabled.

Modify start_smart_selection_action_menu to generate the adaptive icons
by calling ArcActivityIconsToImageSkias.

BUG=1083331

Change-Id: I64a14c5459676593ceeedb442894ca9abe2cebe9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2305816Reviewed-by: default avatarDavid Jacobo <djacobo@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Commit-Queue: Nancy Wang <nancylingwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#792587}
parent 8c0b4876
...@@ -3816,6 +3816,8 @@ static_library("browser") { ...@@ -3816,6 +3816,8 @@ static_library("browser") {
if (is_chromeos) { if (is_chromeos) {
sources += [ sources += [
"apps/app_service/arc_activity_adaptive_icon_impl.cc",
"apps/app_service/arc_activity_adaptive_icon_impl.h",
"apps/app_service/arc_apps.cc", "apps/app_service/arc_apps.cc",
"apps/app_service/arc_apps.h", "apps/app_service/arc_apps.h",
"apps/app_service/arc_apps_factory.cc", "apps/app_service/arc_apps_factory.cc",
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
...@@ -257,6 +256,11 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> { ...@@ -257,6 +256,11 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> {
: size_hint_in_dip_(size_hint_in_dip), : size_hint_in_dip_(size_hint_in_dip),
image_skia_callback_(std::move(callback)) {} image_skia_callback_(std::move(callback)) {}
explicit IconLoadingPipeline(
base::OnceCallback<void(const std::vector<gfx::ImageSkia>& icons)>
callback)
: arc_activity_icons_callback_(std::move(callback)) {}
void LoadWebAppIcon(const std::string& web_app_id, void LoadWebAppIcon(const std::string& web_app_id,
const GURL& launch_url, const GURL& launch_url,
const web_app::AppIconManager& icon_manager, const web_app::AppIconManager& icon_manager,
...@@ -280,6 +284,10 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> { ...@@ -280,6 +284,10 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> {
// then apply the mask. // then apply the mask.
void LoadCompositeImages(const std::vector<uint8_t>& foreground_data, void LoadCompositeImages(const std::vector<uint8_t>& foreground_data,
const std::vector<uint8_t>& background_data); const std::vector<uint8_t>& background_data);
// Loads icons for ARC activities.
void LoadArcActivityIcons(
const std::vector<arc::mojom::ActivityIconPtr>& icons);
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
private: private:
...@@ -289,6 +297,13 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> { ...@@ -289,6 +297,13 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> {
if (!callback_.is_null()) { if (!callback_.is_null()) {
std::move(callback_).Run(apps::mojom::IconValue::New()); std::move(callback_).Run(apps::mojom::IconValue::New());
} }
if (!image_skia_callback_.is_null()) {
std::move(image_skia_callback_).Run(gfx::ImageSkia());
}
if (!arc_activity_icons_callback_.is_null()) {
std::move(arc_activity_icons_callback_)
.Run(std::vector<gfx::ImageSkia>());
}
} }
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
...@@ -300,6 +315,9 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> { ...@@ -300,6 +315,9 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> {
void CompositeImagesAndApplyMask(bool is_foreground, void CompositeImagesAndApplyMask(bool is_foreground,
const gfx::ImageSkia& image); const gfx::ImageSkia& image);
void OnArcActivityIconLoaded(gfx::ImageSkia* arc_activity_icon,
const gfx::ImageSkia& icon);
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
void MaybeApplyEffectsAndComplete(const gfx::ImageSkia image); void MaybeApplyEffectsAndComplete(const gfx::ImageSkia image);
...@@ -340,6 +358,11 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> { ...@@ -340,6 +358,11 @@ class IconLoadingPipeline : public base::RefCounted<IconLoadingPipeline> {
bool background_is_set_ = false; bool background_is_set_ = false;
base::OnceCallback<void(const gfx::ImageSkia& icon)> image_skia_callback_; base::OnceCallback<void(const gfx::ImageSkia& icon)> image_skia_callback_;
std::vector<gfx::ImageSkia> arc_activity_icons_;
size_t count_ = 0;
base::OnceCallback<void(const std::vector<gfx::ImageSkia>& icon)>
arc_activity_icons_callback_;
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
std::unique_ptr<arc::IconDecodeRequest> arc_icon_decode_request_; std::unique_ptr<arc::IconDecodeRequest> arc_icon_decode_request_;
std::unique_ptr<arc::IconDecodeRequest> arc_foreground_icon_decode_request_; std::unique_ptr<arc::IconDecodeRequest> arc_foreground_icon_decode_request_;
...@@ -556,6 +579,35 @@ void IconLoadingPipeline::LoadCompositeImages( ...@@ -556,6 +579,35 @@ void IconLoadingPipeline::LoadCompositeImages(
background_data); background_data);
} }
void IconLoadingPipeline::LoadArcActivityIcons(
const std::vector<arc::mojom::ActivityIconPtr>& icons) {
arc_activity_icons_.resize(icons.size());
DCHECK_EQ(0U, count_);
for (size_t i = 0; i < icons.size(); i++) {
if (!icons[i] || !icons[i]->icon_png_data) {
++count_;
continue;
}
constexpr size_t kMaxIconSizeInPx = 200;
if (icons[i]->width > kMaxIconSizeInPx ||
icons[i]->height > kMaxIconSizeInPx || icons[i]->width == 0 ||
icons[i]->height == 0) {
++count_;
continue;
}
apps::ArcRawIconPngDataToImageSkia(
std::move(icons[i]->icon_png_data), icons[i]->width,
base::BindOnce(&IconLoadingPipeline::OnArcActivityIconLoaded,
base::WrapRefCounted(this), &arc_activity_icons_[i]));
}
if (count_ == arc_activity_icons_.size() && !image_skia_callback_.is_null()) {
std::move(arc_activity_icons_callback_).Run(arc_activity_icons_);
}
}
std::unique_ptr<arc::IconDecodeRequest> std::unique_ptr<arc::IconDecodeRequest>
IconLoadingPipeline::CreateArcIconDecodeRequest( IconLoadingPipeline::CreateArcIconDecodeRequest(
base::OnceCallback<void(const gfx::ImageSkia& icon)> callback, base::OnceCallback<void(const gfx::ImageSkia& icon)> callback,
...@@ -587,7 +639,8 @@ void IconLoadingPipeline::CompositeImagesAndApplyMask( ...@@ -587,7 +639,8 @@ void IconLoadingPipeline::CompositeImagesAndApplyMask(
background_image_ = image; background_image_ = image;
} }
if (!foreground_is_set_ || !background_is_set_ || callback_.is_null()) { if (!foreground_is_set_ || !background_is_set_ ||
image_skia_callback_.is_null()) {
return; return;
} }
...@@ -605,6 +658,19 @@ void IconLoadingPipeline::CompositeImagesAndApplyMask( ...@@ -605,6 +658,19 @@ void IconLoadingPipeline::CompositeImagesAndApplyMask(
skia::ImageOperations::RESIZE_BEST, skia::ImageOperations::RESIZE_BEST,
gfx::Size(size_hint_in_dip_, size_hint_in_dip_))); gfx::Size(size_hint_in_dip_, size_hint_in_dip_)));
} }
void IconLoadingPipeline::OnArcActivityIconLoaded(
gfx::ImageSkia* arc_activity_icon,
const gfx::ImageSkia& icon) {
DCHECK(arc_activity_icon);
++count_;
*arc_activity_icon = icon;
if (count_ == arc_activity_icons_.size() &&
!arc_activity_icons_callback_.is_null()) {
std::move(arc_activity_icons_callback_).Run(arc_activity_icons_);
}
}
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
void IconLoadingPipeline::MaybeApplyEffectsAndComplete( void IconLoadingPipeline::MaybeApplyEffectsAndComplete(
...@@ -825,6 +891,20 @@ void ArcRawIconPngDataToImageSkia( ...@@ -825,6 +891,20 @@ void ArcRawIconPngDataToImageSkia(
std::move(icon->foreground_icon_png_data.value()), std::move(icon->foreground_icon_png_data.value()),
std::move(icon->background_icon_png_data.value())); std::move(icon->background_icon_png_data.value()));
} }
void ArcActivityIconsToImageSkias(
const std::vector<arc::mojom::ActivityIconPtr>& icons,
base::OnceCallback<void(const std::vector<gfx::ImageSkia>& icons)>
callback) {
if (icons.empty()) {
std::move(callback).Run(std::vector<gfx::ImageSkia>{});
return;
}
scoped_refptr<IconLoadingPipeline> icon_loader =
base::MakeRefCounted<IconLoadingPipeline>(std::move(callback));
icon_loader->LoadArcActivityIcons(icons);
}
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
void ApplyIconEffects(IconEffects icon_effects, void ApplyIconEffects(IconEffects icon_effects,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROME_BROWSER_APPS_APP_SERVICE_APP_ICON_FACTORY_H_ #define CHROME_BROWSER_APPS_APP_SERVICE_APP_ICON_FACTORY_H_
#include <string> #include <string>
#include <vector>
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "components/arc/mojom/app.mojom.h" #include "components/arc/mojom/app.mojom.h"
#include "components/arc/mojom/intent_helper.mojom.h"
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
namespace content { namespace content {
...@@ -63,6 +65,11 @@ void ArcRawIconPngDataToImageSkia( ...@@ -63,6 +65,11 @@ void ArcRawIconPngDataToImageSkia(
arc::mojom::RawIconPngDataPtr icon, arc::mojom::RawIconPngDataPtr icon,
int size_hint_in_dip, int size_hint_in_dip,
base::OnceCallback<void(const gfx::ImageSkia& icon)> callback); base::OnceCallback<void(const gfx::ImageSkia& icon)> callback);
void ArcActivityIconsToImageSkias(
const std::vector<arc::mojom::ActivityIconPtr>& icons,
base::OnceCallback<void(const std::vector<gfx::ImageSkia>& icons)>
callback);
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
// Modifies |image_skia| to apply icon post-processing effects like badging and // Modifies |image_skia| to apply icon post-processing effects like badging and
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "cc/test/pixel_comparator.h" #include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test_utils.h" #include "cc/test/pixel_test_utils.h"
...@@ -16,6 +17,11 @@ ...@@ -16,6 +17,11 @@
#include "content/public/test/browser_task_environment.h" #include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/arc/icon_decode_request.h"
#include "components/arc/mojom/intent_helper.mojom.h"
#endif
class AppIconFactoryTest : public testing::Test { class AppIconFactoryTest : public testing::Test {
public: public:
base::FilePath GetPath() { base::FilePath GetPath() {
...@@ -56,6 +62,20 @@ class AppIconFactoryTest : public testing::Test { ...@@ -56,6 +62,20 @@ class AppIconFactoryTest : public testing::Test {
run_loop_.Run(); run_loop_.Run();
} }
std::string GetPngData(const std::string file_name) {
base::FilePath base_path;
std::string png_data_as_string;
CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &base_path));
base::FilePath icon_file_path = base_path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
.AppendASCII("arc")
.AppendASCII(file_name);
CHECK(base::PathExists(icon_file_path));
CHECK(base::ReadFileToString(icon_file_path, &png_data_as_string));
return png_data_as_string;
}
protected: protected:
content::BrowserTaskEnvironment task_env_{}; content::BrowserTaskEnvironment task_env_{};
base::ScopedTempDir tmp_dir_{}; base::ScopedTempDir tmp_dir_{};
...@@ -138,3 +158,121 @@ TEST_F(AppIconFactoryTest, LoadFromFileFallbackDoesNotReturn) { ...@@ -138,3 +158,121 @@ TEST_F(AppIconFactoryTest, LoadFromFileFallbackDoesNotReturn) {
EXPECT_TRUE(fallback_called); EXPECT_TRUE(fallback_called);
EXPECT_FALSE(result.is_null()); EXPECT_FALSE(result.is_null());
} }
#if defined(OS_CHROMEOS)
TEST_F(AppIconFactoryTest, ArcNonAdaptiveIconToImageSkia) {
arc::IconDecodeRequest::DisableSafeDecodingForTesting();
std::string png_data_as_string = GetPngData("icon_100p.png");
arc::mojom::RawIconPngDataPtr icon = arc::mojom::RawIconPngData::New(
false,
std::vector<uint8_t>(png_data_as_string.begin(),
png_data_as_string.end()),
std::vector<uint8_t>(), std::vector<uint8_t>());
bool callback_called = false;
apps::ArcRawIconPngDataToImageSkia(
std::move(icon), 100,
base::BindOnce(
[](bool* called, base::OnceClosure quit,
const gfx::ImageSkia& image) {
if (!image.isNull()) {
*called = true;
}
std::move(quit).Run();
},
base::Unretained(&callback_called), run_loop_.QuitClosure()));
run_loop_.Run();
EXPECT_TRUE(callback_called);
}
TEST_F(AppIconFactoryTest, ArcAdaptiveIconToImageSkia) {
arc::IconDecodeRequest::DisableSafeDecodingForTesting();
std::string png_data_as_string = GetPngData("icon_100p.png");
arc::mojom::RawIconPngDataPtr icon = arc::mojom::RawIconPngData::New(
true, std::vector<uint8_t>(),
std::vector<uint8_t>(png_data_as_string.begin(),
png_data_as_string.end()),
std::vector<uint8_t>(png_data_as_string.begin(),
png_data_as_string.end()));
bool callback_called = false;
apps::ArcRawIconPngDataToImageSkia(
std::move(icon), 100,
base::BindOnce(
[](bool* called, base::OnceClosure quit,
const gfx::ImageSkia& image) {
if (!image.isNull()) {
*called = true;
}
std::move(quit).Run();
},
base::Unretained(&callback_called), run_loop_.QuitClosure()));
run_loop_.Run();
EXPECT_TRUE(callback_called);
}
TEST_F(AppIconFactoryTest, ArcActivityIconsToImageSkias) {
arc::IconDecodeRequest::DisableSafeDecodingForTesting();
std::string png_data_as_string = GetPngData("icon_100p.png");
std::vector<arc::mojom::ActivityIconPtr> icons;
icons.emplace_back(
arc::mojom::ActivityIcon::New(arc::mojom::ActivityName::New("p0", "a0"),
100, 100, std::vector<uint8_t>()));
icons.emplace_back(arc::mojom::ActivityIcon::New(
arc::mojom::ActivityName::New("p0", "a0"), 100, 100,
std::vector<uint8_t>(),
arc::mojom::RawIconPngData::New(
false,
std::vector<uint8_t>(png_data_as_string.begin(),
png_data_as_string.end()),
std::vector<uint8_t>(), std::vector<uint8_t>())));
icons.emplace_back(arc::mojom::ActivityIcon::New(
arc::mojom::ActivityName::New("p0", "a0"), 201, 201,
std::vector<uint8_t>(),
arc::mojom::RawIconPngData::New(
false,
std::vector<uint8_t>(png_data_as_string.begin(),
png_data_as_string.end()),
std::vector<uint8_t>(), std::vector<uint8_t>())));
icons.emplace_back(arc::mojom::ActivityIcon::New(
arc::mojom::ActivityName::New("p1", "a1"), 100, 100,
std::vector<uint8_t>(),
arc::mojom::RawIconPngData::New(
true, std::vector<uint8_t>(),
std::vector<uint8_t>(png_data_as_string.begin(),
png_data_as_string.end()),
std::vector<uint8_t>(png_data_as_string.begin(),
png_data_as_string.end()))));
std::vector<gfx::ImageSkia> result;
bool callback_called = false;
apps::ArcActivityIconsToImageSkias(
icons, base::BindOnce(
[](bool* called, std::vector<gfx::ImageSkia>* result,
base::OnceClosure quit,
const std::vector<gfx::ImageSkia>& images) {
*called = true;
for (auto image : images) {
result->emplace_back(image);
}
std::move(quit).Run();
},
base::Unretained(&callback_called), base::Unretained(&result),
run_loop_.QuitClosure()));
run_loop_.Run();
EXPECT_TRUE(callback_called);
EXPECT_EQ(4U, result.size());
if (result.size() == 4U) {
EXPECT_TRUE(result[0].isNull());
EXPECT_FALSE(result[1].isNull());
EXPECT_TRUE(result[2].isNull());
EXPECT_FALSE(result[3].isNull());
}
}
#endif
// Copyright 2020 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_activity_adaptive_icon_impl.h"
#include <utility>
#include "base/bind.h"
#include "chrome/browser/apps/app_service/app_icon_factory.h"
#include "components/arc/intent_helper/adaptive_icon_delegate.h"
namespace apps {
ArcActivityAdaptiveIconImpl::ArcActivityAdaptiveIconImpl() = default;
ArcActivityAdaptiveIconImpl::~ArcActivityAdaptiveIconImpl() = default;
void ArcActivityAdaptiveIconImpl::GenerateAdaptiveIcons(
const std::vector<arc::mojom::ActivityIconPtr>& icons,
AdaptiveIconDelegateCallback callback) {
apps::ArcActivityIconsToImageSkias(
icons, base::BindOnce(
[](AdaptiveIconDelegateCallback callback,
const std::vector<gfx::ImageSkia>& images) {
std::move(callback).Run(images);
},
std::move(callback)));
}
} // namespace apps
// Copyright 2020 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_ACTIVITY_ADAPTIVE_ICON_IMPL_H_
#define CHROME_BROWSER_APPS_APP_SERVICE_ARC_ACTIVITY_ADAPTIVE_ICON_IMPL_H_
#include <vector>
#include "components/arc/intent_helper/adaptive_icon_delegate.h"
#include "components/arc/mojom/intent_helper.mojom.h"
namespace arc {
class AdaptiveIconDelegate;
}
namespace apps {
// An icon loader specific to an activity icon from ARC, to generate the
// adaptive icon with the raw foreground and background icon images.
class ArcActivityAdaptiveIconImpl : public arc::AdaptiveIconDelegate {
public:
ArcActivityAdaptiveIconImpl();
~ArcActivityAdaptiveIconImpl() override;
ArcActivityAdaptiveIconImpl(const ArcActivityAdaptiveIconImpl&) = delete;
ArcActivityAdaptiveIconImpl& operator=(const ArcActivityAdaptiveIconImpl&) =
delete;
void GenerateAdaptiveIcons(
const std::vector<arc::mojom::ActivityIconPtr>& icons,
AdaptiveIconDelegateCallback callback) override;
};
} // namespace apps
#endif // CHROME_BROWSER_APPS_APP_SERVICE_ARC_ACTIVITY_ADAPTIVE_ICON_IMPL_H_
...@@ -587,6 +587,10 @@ ArcApps::ArcApps(Profile* profile, apps::AppServiceProxy* proxy) ...@@ -587,6 +587,10 @@ ArcApps::ArcApps(Profile* profile, apps::AppServiceProxy* proxy)
auto* intent_helper_bridge = auto* intent_helper_bridge =
arc::ArcIntentHelperBridge::GetForBrowserContext(profile_); arc::ArcIntentHelperBridge::GetForBrowserContext(profile_);
if (intent_helper_bridge) { if (intent_helper_bridge) {
if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
intent_helper_bridge->SetAdaptiveIconDelegate(
&arc_activity_adaptive_icon_impl_);
}
arc_intent_helper_observer_.Add(intent_helper_bridge); arc_intent_helper_observer_.Add(intent_helper_bridge);
} }
...@@ -633,6 +637,13 @@ void ArcApps::Shutdown() { ...@@ -633,6 +637,13 @@ void ArcApps::Shutdown() {
} }
arc_icon_once_loader_.StopObserving(prefs); arc_icon_once_loader_.StopObserving(prefs);
auto* intent_helper_bridge =
arc::ArcIntentHelperBridge::GetForBrowserContext(profile_);
if (intent_helper_bridge &&
base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
intent_helper_bridge->SetAdaptiveIconDelegate(nullptr);
}
arc_intent_helper_observer_.RemoveAll(); arc_intent_helper_observer_.RemoveAll();
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "chrome/browser/apps/app_service/app_icon_factory.h" #include "chrome/browser/apps/app_service/app_icon_factory.h"
#include "chrome/browser/apps/app_service/app_notifications.h" #include "chrome/browser/apps/app_service/app_notifications.h"
#include "chrome/browser/apps/app_service/arc_activity_adaptive_icon_impl.h"
#include "chrome/browser/apps/app_service/arc_icon_once_loader.h" #include "chrome/browser/apps/app_service/arc_icon_once_loader.h"
#include "chrome/browser/apps/app_service/icon_key_util.h" #include "chrome/browser/apps/app_service/icon_key_util.h"
#include "chrome/browser/apps/app_service/paused_apps.h" #include "chrome/browser/apps/app_service/paused_apps.h"
...@@ -189,6 +190,7 @@ class ArcApps : public KeyedService, ...@@ -189,6 +190,7 @@ class ArcApps : public KeyedService,
Profile* const profile_; Profile* const profile_;
ArcIconOnceLoader arc_icon_once_loader_; ArcIconOnceLoader arc_icon_once_loader_;
ArcActivityAdaptiveIconImpl arc_activity_adaptive_icon_impl_;
apps_util::IncrementingIconKeyFactory icon_key_factory_; apps_util::IncrementingIconKeyFactory icon_key_factory_;
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h" #include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/apps/app_service/app_icon_factory.h"
#include "chrome/common/chrome_features.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "components/arc/arc_features.h" #include "components/arc/arc_features.h"
#include "components/arc/arc_service_manager.h" #include "components/arc/arc_service_manager.h"
...@@ -23,7 +25,6 @@ ...@@ -23,7 +25,6 @@
#include "components/arc/session/arc_bridge_service.h" #include "components/arc/session/arc_bridge_service.h"
#include "components/renderer_context_menu/render_view_context_menu_proxy.h" #include "components/renderer_context_menu/render_view_context_menu_proxy.h"
#include "content/public/browser/context_menu_params.h" #include "content/public/browser/context_menu_params.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/image/image_skia_operations.h"
namespace arc { namespace arc {
...@@ -121,11 +122,8 @@ void StartSmartSelectionActionMenu::HandleTextSelectionActions( ...@@ -121,11 +122,8 @@ void StartSmartSelectionActionMenu::HandleTextSelectionActions(
/*title=*/base::UTF8ToUTF16(actions_[i]->title)); /*title=*/base::UTF8ToUTF16(actions_[i]->title));
if (actions_[i]->icon) { if (actions_[i]->icon) {
gfx::Image icon = GetIconImage(std::move(actions_[i]->icon)); UpdateMenuIcon(IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1 + i,
if (!icon.IsEmpty()) { std::move(actions_[i]->icon));
proxy_->UpdateMenuIcon(
IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1 + i, icon);
}
} }
} }
...@@ -143,19 +141,30 @@ void StartSmartSelectionActionMenu::HandleTextSelectionActions( ...@@ -143,19 +141,30 @@ void StartSmartSelectionActionMenu::HandleTextSelectionActions(
proxy_->RemoveAdjacentSeparators(); proxy_->RemoveAdjacentSeparators();
} }
gfx::Image StartSmartSelectionActionMenu::GetIconImage( void StartSmartSelectionActionMenu::UpdateMenuIcon(
int command_id,
mojom::ActivityIconPtr icon) { mojom::ActivityIconPtr icon) {
constexpr size_t kBytesPerPixel = 4; // BGRA constexpr size_t kBytesPerPixel = 4; // BGRA
if (icon->width > kMaxIconSizeInPx || icon->height > kMaxIconSizeInPx || if (icon->width > kMaxIconSizeInPx || icon->height > kMaxIconSizeInPx ||
icon->width == 0 || icon->height == 0 || icon->width == 0 || icon->height == 0 ||
icon->icon.size() != (icon->width * icon->height * kBytesPerPixel)) { icon->icon.size() != (icon->width * icon->height * kBytesPerPixel)) {
return gfx::Image(); return;
}
if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
DCHECK(icon->icon_png_data);
apps::ArcRawIconPngDataToImageSkia(
std::move(icon->icon_png_data), kSmallIconSizeInDip,
base::BindOnce(&StartSmartSelectionActionMenu::SetMenuIcon,
weak_ptr_factory_.GetWeakPtr(), command_id));
return;
} }
SkBitmap bitmap; SkBitmap bitmap;
bitmap.allocPixels(SkImageInfo::MakeN32Premul(icon->width, icon->height)); bitmap.allocPixels(SkImageInfo::MakeN32Premul(icon->width, icon->height));
if (!bitmap.getPixels()) if (!bitmap.getPixels())
return gfx::Image(); return;
DCHECK_GE(bitmap.computeByteSize(), icon->icon.size()); DCHECK_GE(bitmap.computeByteSize(), icon->icon.size());
memcpy(bitmap.getPixels(), &icon->icon.front(), icon->icon.size()); memcpy(bitmap.getPixels(), &icon->icon.front(), icon->icon.size());
...@@ -165,7 +174,12 @@ gfx::Image StartSmartSelectionActionMenu::GetIconImage( ...@@ -165,7 +174,12 @@ gfx::Image StartSmartSelectionActionMenu::GetIconImage(
original, skia::ImageOperations::RESIZE_BEST, original, skia::ImageOperations::RESIZE_BEST,
gfx::Size(kSmallIconSizeInDip, kSmallIconSizeInDip))); gfx::Size(kSmallIconSizeInDip, kSmallIconSizeInDip)));
return gfx::Image(icon_small); SetMenuIcon(command_id, icon_small);
}
void StartSmartSelectionActionMenu::SetMenuIcon(int command_id,
const gfx::ImageSkia& image) {
proxy_->UpdateMenuIcon(command_id, gfx::Image(image));
} }
} // namespace arc } // namespace arc
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "components/arc/mojom/intent_helper.mojom.h" #include "components/arc/mojom/intent_helper.mojom.h"
#include "components/renderer_context_menu/render_view_context_menu_observer.h" #include "components/renderer_context_menu/render_view_context_menu_observer.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
class RenderViewContextMenuProxy; class RenderViewContextMenuProxy;
...@@ -35,7 +36,9 @@ class StartSmartSelectionActionMenu : public RenderViewContextMenuObserver { ...@@ -35,7 +36,9 @@ class StartSmartSelectionActionMenu : public RenderViewContextMenuObserver {
void HandleTextSelectionActions( void HandleTextSelectionActions(
std::vector<mojom::TextSelectionActionPtr> actions); std::vector<mojom::TextSelectionActionPtr> actions);
gfx::Image GetIconImage(mojom::ActivityIconPtr icon); void UpdateMenuIcon(int command_id, mojom::ActivityIconPtr icon);
void SetMenuIcon(int command_id, const gfx::ImageSkia& image);
RenderViewContextMenuProxy* const proxy_; // Owned by RenderViewContextMenu. RenderViewContextMenuProxy* const proxy_; // Owned by RenderViewContextMenu.
......
...@@ -30,6 +30,7 @@ static_library("arc") { ...@@ -30,6 +30,7 @@ static_library("arc") {
"ime/arc_ime_service.h", "ime/arc_ime_service.h",
"intent_helper/activity_icon_loader.cc", "intent_helper/activity_icon_loader.cc",
"intent_helper/activity_icon_loader.h", "intent_helper/activity_icon_loader.h",
"intent_helper/adaptive_icon_delegate.h",
"intent_helper/arc_intent_helper_bridge.cc", "intent_helper/arc_intent_helper_bridge.cc",
"intent_helper/arc_intent_helper_bridge.h", "intent_helper/arc_intent_helper_bridge.h",
"intent_helper/arc_intent_helper_observer.h", "intent_helper/arc_intent_helper_observer.h",
......
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
#include "base/task/thread_pool.h" #include "base/task/thread_pool.h"
#include "components/arc/arc_service_manager.h" #include "components/arc/arc_service_manager.h"
#include "components/arc/arc_util.h" #include "components/arc/arc_util.h"
#include "components/arc/intent_helper/adaptive_icon_delegate.h"
#include "components/arc/session/arc_bridge_service.h" #include "components/arc/session/arc_bridge_service.h"
#include "ui/base/layout.h" #include "ui/base/layout.h"
#include "ui/gfx/codec/png_codec.h" #include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/image/image_skia_operations.h"
namespace arc { namespace arc {
...@@ -80,6 +80,14 @@ mojom::IntentHelperInstance* GetInstanceForRequestActivityIcons( ...@@ -80,6 +80,14 @@ mojom::IntentHelperInstance* GetInstanceForRequestActivityIcons(
return instance; return instance;
} }
ActivityIconLoader::ActivityName GenerateActivityName(
const mojom::ActivityIconPtr& icon) {
return ActivityIconLoader::ActivityName(
icon->activity->package_name, icon->activity->activity_name.has_value()
? (*icon->activity->activity_name)
: std::string());
}
// Encodes the |image| as PNG data considering scale factor, and returns it as // Encodes the |image| as PNG data considering scale factor, and returns it as
// data: URL. // data: URL.
scoped_refptr<base::RefCountedData<GURL>> GeneratePNGDataUrl( scoped_refptr<base::RefCountedData<GURL>> GeneratePNGDataUrl(
...@@ -98,6 +106,23 @@ scoped_refptr<base::RefCountedData<GURL>> GeneratePNGDataUrl( ...@@ -98,6 +106,23 @@ scoped_refptr<base::RefCountedData<GURL>> GeneratePNGDataUrl(
new base::RefCountedData<GURL>(GURL(kPngDataUrlPrefix + encoded))); new base::RefCountedData<GURL>(GURL(kPngDataUrlPrefix + encoded)));
} }
ActivityIconLoader::Icons ResizeIconsInternal(const gfx::ImageSkia& image,
ui::ScaleFactor scale_factor) {
// Resize the original icon to the sizes intent_helper needs.
gfx::ImageSkia icon_large(gfx::ImageSkiaOperations::CreateResizedImage(
image, skia::ImageOperations::RESIZE_BEST,
gfx::Size(kLargeIconSizeInDip, kLargeIconSizeInDip)));
gfx::Image icon20(icon_large);
gfx::ImageSkia icon_small(gfx::ImageSkiaOperations::CreateResizedImage(
image, skia::ImageOperations::RESIZE_BEST,
gfx::Size(kSmallIconSizeInDip, kSmallIconSizeInDip)));
gfx::Image icon16(icon_small);
return ActivityIconLoader::Icons(
icon16, icon20, GeneratePNGDataUrl(icon_small, scale_factor));
}
std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> ResizeAndEncodeIcons( std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> ResizeAndEncodeIcons(
std::vector<mojom::ActivityIconPtr> icons, std::vector<mojom::ActivityIconPtr> icons,
ui::ScaleFactor scale_factor) { ui::ScaleFactor scale_factor) {
...@@ -120,24 +145,22 @@ std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> ResizeAndEncodeIcons( ...@@ -120,24 +145,22 @@ std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> ResizeAndEncodeIcons(
gfx::ImageSkia original(gfx::ImageSkia::CreateFrom1xBitmap(bitmap)); gfx::ImageSkia original(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
// Resize the original icon to the sizes intent_helper needs. result->insert(std::make_pair(GenerateActivityName(icon),
gfx::ImageSkia icon_large(gfx::ImageSkiaOperations::CreateResizedImage( ResizeIconsInternal(original, scale_factor)));
original, skia::ImageOperations::RESIZE_BEST, }
gfx::Size(kLargeIconSizeInDip, kLargeIconSizeInDip)));
gfx::ImageSkia icon_small(gfx::ImageSkiaOperations::CreateResizedImage( return result;
original, skia::ImageOperations::RESIZE_BEST, }
gfx::Size(kSmallIconSizeInDip, kSmallIconSizeInDip)));
gfx::Image icon16(icon_small); std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> ResizeIcons(
gfx::Image icon20(icon_large); std::vector<ActivityIconLoader::ActivityName> activity_names,
const std::vector<gfx::ImageSkia>& images,
const std::string activity_name = icon->activity->activity_name.has_value() ui::ScaleFactor scale_factor) {
? (*icon->activity->activity_name) DCHECK_EQ(activity_names.size(), images.size());
: std::string(); auto result = std::make_unique<ActivityIconLoader::ActivityToIconsMap>();
for (size_t i = 0; i < activity_names.size(); ++i) {
result->insert(std::make_pair( result->insert(std::make_pair(
ActivityIconLoader::ActivityName(icon->activity->package_name, activity_names[i], ResizeIconsInternal(images[i], scale_factor)));
activity_name),
ActivityIconLoader::Icons(
icon16, icon20, GeneratePNGDataUrl(icon_small, scale_factor))));
} }
return result; return result;
...@@ -170,6 +193,11 @@ ActivityIconLoader::ActivityIconLoader() ...@@ -170,6 +193,11 @@ ActivityIconLoader::ActivityIconLoader()
ActivityIconLoader::~ActivityIconLoader() = default; ActivityIconLoader::~ActivityIconLoader() = default;
void ActivityIconLoader::SetAdaptiveIconDelegate(
AdaptiveIconDelegate* delegate) {
delegate_ = delegate;
}
void ActivityIconLoader::InvalidateIcons(const std::string& package_name) { void ActivityIconLoader::InvalidateIcons(const std::string& package_name) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (auto it = cached_icons_.begin(); it != cached_icons_.end();) { for (auto it = cached_icons_.begin(); it != cached_icons_.end();) {
...@@ -235,6 +263,13 @@ void ActivityIconLoader::AddCacheEntryForTesting(const ActivityName& activity) { ...@@ -235,6 +263,13 @@ void ActivityIconLoader::AddCacheEntryForTesting(const ActivityName& activity) {
std::make_pair(activity, Icons(gfx::Image(), gfx::Image(), nullptr))); std::make_pair(activity, Icons(gfx::Image(), gfx::Image(), nullptr)));
} }
void ActivityIconLoader::OnIconsReadyForTesting(
std::unique_ptr<ActivityToIconsMap> cached_result,
OnIconsReadyCallback cb,
std::vector<mojom::ActivityIconPtr> icons) {
OnIconsReady(std::move(cached_result), std::move(cb), std::move(icons));
}
// static // static
bool ActivityIconLoader::HasIconsReadyCallbackRun(GetResult result) { bool ActivityIconLoader::HasIconsReadyCallbackRun(GetResult result) {
switch (result) { switch (result) {
...@@ -253,6 +288,21 @@ void ActivityIconLoader::OnIconsReady( ...@@ -253,6 +288,21 @@ void ActivityIconLoader::OnIconsReady(
OnIconsReadyCallback cb, OnIconsReadyCallback cb,
std::vector<mojom::ActivityIconPtr> icons) { std::vector<mojom::ActivityIconPtr> icons) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (delegate_) {
std::vector<ActivityName> actvity_names;
for (const auto& icon : icons)
actvity_names.emplace_back(GenerateActivityName(icon));
delegate_->GenerateAdaptiveIcons(
icons,
base::BindOnce(&ActivityIconLoader::OnAdaptiveIconGenerated,
weak_ptr_factory_.GetWeakPtr(), std::move(actvity_names),
std::move(cached_result), std::move(cb)));
return;
}
// TODO(crbug.com/1083331): Remove when the adaptive icon feature is enabled
// by default.
base::ThreadPool::PostTaskAndReplyWithResult( base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, FROM_HERE,
base::BindOnce(&ResizeAndEncodeIcons, std::move(icons), scale_factor_), base::BindOnce(&ResizeAndEncodeIcons, std::move(icons), scale_factor_),
...@@ -261,6 +311,22 @@ void ActivityIconLoader::OnIconsReady( ...@@ -261,6 +311,22 @@ void ActivityIconLoader::OnIconsReady(
std::move(cb))); std::move(cb)));
} }
void ActivityIconLoader::OnAdaptiveIconGenerated(
std::vector<ActivityName> actvity_names,
std::unique_ptr<ActivityToIconsMap> cached_result,
OnIconsReadyCallback cb,
const std::vector<gfx::ImageSkia>& adaptive_icons) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&ResizeIcons, std::move(actvity_names), adaptive_icons,
scale_factor_),
base::BindOnce(&ActivityIconLoader::OnIconsResized,
weak_ptr_factory_.GetWeakPtr(), std::move(cached_result),
std::move(cb)));
}
void ActivityIconLoader::OnIconsResized( void ActivityIconLoader::OnIconsResized(
std::unique_ptr<ActivityToIconsMap> cached_result, std::unique_ptr<ActivityToIconsMap> cached_result,
OnIconsReadyCallback cb, OnIconsReadyCallback cb,
......
...@@ -18,9 +18,13 @@ ...@@ -18,9 +18,13 @@
#include "components/arc/mojom/intent_helper.mojom.h" #include "components/arc/mojom/intent_helper.mojom.h"
#include "ui/base/layout.h" #include "ui/base/layout.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace arc { namespace arc {
class AdaptiveIconDelegate;
namespace internal { namespace internal {
// A class which retrieves an activity icon from ARC. // A class which retrieves an activity icon from ARC.
...@@ -71,6 +75,8 @@ class ActivityIconLoader { ...@@ -71,6 +75,8 @@ class ActivityIconLoader {
ActivityIconLoader(); ActivityIconLoader();
~ActivityIconLoader(); ~ActivityIconLoader();
void SetAdaptiveIconDelegate(AdaptiveIconDelegate* delegate);
// Removes icons associated with |package_name| from the cache. // Removes icons associated with |package_name| from the cache.
void InvalidateIcons(const std::string& package_name); void InvalidateIcons(const std::string& package_name);
...@@ -86,6 +92,10 @@ class ActivityIconLoader { ...@@ -86,6 +92,10 @@ class ActivityIconLoader {
std::unique_ptr<ActivityToIconsMap> result); std::unique_ptr<ActivityToIconsMap> result);
void AddCacheEntryForTesting(const ActivityName& activity); void AddCacheEntryForTesting(const ActivityName& activity);
void OnIconsReadyForTesting(std::unique_ptr<ActivityToIconsMap> cached_result,
OnIconsReadyCallback cb,
std::vector<mojom::ActivityIconPtr> icons);
// Returns true if |result| indicates that the |cb| object passed to // Returns true if |result| indicates that the |cb| object passed to
// GetActivityIcons() has already called. // GetActivityIcons() has already called.
static bool HasIconsReadyCallbackRun(GetResult result); static bool HasIconsReadyCallbackRun(GetResult result);
...@@ -98,6 +108,13 @@ class ActivityIconLoader { ...@@ -98,6 +108,13 @@ class ActivityIconLoader {
OnIconsReadyCallback cb, OnIconsReadyCallback cb,
std::vector<mojom::ActivityIconPtr> icons); std::vector<mojom::ActivityIconPtr> icons);
// A function called when the adaptive icons are generated.
void OnAdaptiveIconGenerated(
std::vector<ActivityName> actvity_names,
std::unique_ptr<ActivityToIconsMap> cached_result,
OnIconsReadyCallback cb,
const std::vector<gfx::ImageSkia>& adaptive_icons);
// A function called when ResizeIcons finishes. Append items in |result| to // A function called when ResizeIcons finishes. Append items in |result| to
// |cached_icons_|. // |cached_icons_|.
void OnIconsResized(std::unique_ptr<ActivityToIconsMap> cached_result, void OnIconsResized(std::unique_ptr<ActivityToIconsMap> cached_result,
...@@ -109,6 +126,9 @@ class ActivityIconLoader { ...@@ -109,6 +126,9 @@ class ActivityIconLoader {
// A map which holds icons in a scale-factor independent form (gfx::Image). // A map which holds icons in a scale-factor independent form (gfx::Image).
ActivityToIconsMap cached_icons_; ActivityToIconsMap cached_icons_;
// A delegate which converts the icon to the adaptive icon.
AdaptiveIconDelegate* delegate_ = nullptr;
THREAD_CHECKER(thread_checker_); THREAD_CHECKER(thread_checker_);
// This must come last to make sure weak pointers are invalidated first. // This must come last to make sure weak pointers are invalidated first.
......
...@@ -9,7 +9,12 @@ ...@@ -9,7 +9,12 @@
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "components/arc/intent_helper/adaptive_icon_delegate.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/image/image_skia.h"
namespace arc { namespace arc {
namespace internal { namespace internal {
...@@ -47,6 +52,39 @@ void OnIconsReady3( ...@@ -47,6 +52,39 @@ void OnIconsReady3(
ActivityIconLoader::ActivityName("p2", "a2"))); ActivityIconLoader::ActivityName("p2", "a2")));
} }
class FakeAdaptiveIconDelegate : public AdaptiveIconDelegate {
public:
FakeAdaptiveIconDelegate() = default;
~FakeAdaptiveIconDelegate() override = default;
FakeAdaptiveIconDelegate(const FakeAdaptiveIconDelegate&) = delete;
FakeAdaptiveIconDelegate& operator=(const FakeAdaptiveIconDelegate&) = delete;
void GenerateAdaptiveIcons(
const std::vector<arc::mojom::ActivityIconPtr>& icons,
AdaptiveIconDelegateCallback callback) override {
++count_;
std::vector<gfx::ImageSkia> result;
for (const auto& icon : icons) {
if (icon && icon->icon_png_data &&
icon->icon_png_data->is_adaptive_icon &&
icon->icon_png_data->foreground_icon_png_data) {
auto png_data(icon->icon_png_data->foreground_icon_png_data.value());
png_data_.emplace_back(std::string(png_data.begin(), png_data.end()));
result.emplace_back(gfx::ImageSkia());
}
}
std::move(callback).Run(std::move(result));
}
std::vector<std::string> png_data() { return png_data_; }
int count() { return count_; }
private:
int count_ = 0;
std::vector<std::string> png_data_;
};
// Tests if InvalidateIcons properly cleans up the cache. // Tests if InvalidateIcons properly cleans up the cache.
TEST(ActivityIconLoaderTest, TestInvalidateIcons) { TEST(ActivityIconLoaderTest, TestInvalidateIcons) {
ActivityIconLoader loader; ActivityIconLoader loader;
...@@ -156,6 +194,129 @@ TEST(ActivityIconLoaderTest, TestOnIconsResized) { ...@@ -156,6 +194,129 @@ TEST(ActivityIconLoaderTest, TestOnIconsResized) {
ActivityIconLoader::ActivityName("p2", "a2"))); ActivityIconLoader::ActivityName("p2", "a2")));
} }
class ActivityIconLoaderOnIconsReadyTest : public ::testing::Test {
public:
ActivityIconLoaderOnIconsReadyTest() = default;
~ActivityIconLoaderOnIconsReadyTest() override = default;
ActivityIconLoaderOnIconsReadyTest(
const ActivityIconLoaderOnIconsReadyTest&) = delete;
ActivityIconLoaderOnIconsReadyTest& operator=(
const ActivityIconLoaderOnIconsReadyTest&) = delete;
void OnIconsReady(std::unique_ptr<ActivityIconLoader::ActivityToIconsMap>
activity_to_icons) {
EXPECT_EQ(4U, activity_to_icons->size());
EXPECT_EQ(1U, activity_to_icons->count(
ActivityIconLoader::ActivityName("p0", "a0")));
EXPECT_EQ(1U, activity_to_icons->count(
ActivityIconLoader::ActivityName("p1", "a1")));
EXPECT_EQ(1U, activity_to_icons->count(
ActivityIconLoader::ActivityName("p2", "a2")));
EXPECT_EQ(1U, activity_to_icons->count(
ActivityIconLoader::ActivityName("p3", "a3")));
if (!on_icon_ready_callback_.is_null())
std::move(on_icon_ready_callback_).Run();
}
void WaitForIconReady() {
base::RunLoop run_loop;
on_icon_ready_callback_ = run_loop.QuitClosure();
run_loop.Run();
}
base::OnceClosure on_icon_ready_callback_;
base::test::TaskEnvironment task_environment_;
base::WeakPtrFactory<ActivityIconLoaderOnIconsReadyTest> weak_ptr_factory_{
this};
};
// Tests OnIconsReady with a delegate.
TEST_F(ActivityIconLoaderOnIconsReadyTest, TestWithDelegate) {
ActivityIconLoader loader;
std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> activity_to_icons(
new ActivityIconLoader::ActivityToIconsMap);
auto activity_name0 = ActivityIconLoader::ActivityName("p0", "a0");
auto activity_name1 = ActivityIconLoader::ActivityName("p1", "a1");
loader.AddCacheEntryForTesting(activity_name0);
loader.AddCacheEntryForTesting(activity_name1);
activity_to_icons->insert(std::make_pair(
activity_name0,
ActivityIconLoader::Icons(gfx::Image(), gfx::Image(), nullptr)));
activity_to_icons->insert(std::make_pair(
activity_name1,
ActivityIconLoader::Icons(gfx::Image(), gfx::Image(), nullptr)));
std::vector<mojom::ActivityIconPtr> icons;
std::string foreground_png_data_as_string0 = "FOREGROUND_ICON_CONTENT_0";
std::string foreground_png_data_as_string1 = "FOREGROUND_ICON_CONTENT_1";
icons.emplace_back(mojom::ActivityIcon::New(
mojom::ActivityName::New("p2", "a2"), 32, 32, std::vector<uint8_t>(),
mojom::RawIconPngData::New(
true, std::vector<uint8_t>(),
std::vector<uint8_t>(foreground_png_data_as_string0.begin(),
foreground_png_data_as_string0.end()),
std::vector<uint8_t>())));
icons.emplace_back(mojom::ActivityIcon::New(
mojom::ActivityName::New("p3", "a3"), 32, 32, std::vector<uint8_t>(),
mojom::RawIconPngData::New(
true, std::vector<uint8_t>(),
std::vector<uint8_t>(foreground_png_data_as_string1.begin(),
foreground_png_data_as_string1.end()),
std::vector<uint8_t>())));
FakeAdaptiveIconDelegate delegate;
loader.SetAdaptiveIconDelegate(&delegate);
// Call OnIconsReady() and check that the cache is properly updated.
loader.OnIconsReadyForTesting(
std::move(activity_to_icons),
base::BindOnce(&ActivityIconLoaderOnIconsReadyTest::OnIconsReady,
weak_ptr_factory_.GetWeakPtr()),
std::move(icons));
EXPECT_EQ(1, delegate.count());
EXPECT_EQ(2U, delegate.png_data().size());
EXPECT_EQ(foreground_png_data_as_string0, delegate.png_data()[0]);
EXPECT_EQ(foreground_png_data_as_string1, delegate.png_data()[1]);
WaitForIconReady();
}
// Tests OnIconsReady without a delegate.
TEST_F(ActivityIconLoaderOnIconsReadyTest, TestWithoutDelegate) {
ActivityIconLoader loader;
std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> activity_to_icons(
new ActivityIconLoader::ActivityToIconsMap);
auto activity_name0 = ActivityIconLoader::ActivityName("p0", "a0");
auto activity_name1 = ActivityIconLoader::ActivityName("p1", "a1");
loader.AddCacheEntryForTesting(activity_name0);
loader.AddCacheEntryForTesting(activity_name1);
activity_to_icons->insert(std::make_pair(
activity_name0,
ActivityIconLoader::Icons(gfx::Image(), gfx::Image(), nullptr)));
activity_to_icons->insert(std::make_pair(
activity_name1,
ActivityIconLoader::Icons(gfx::Image(), gfx::Image(), nullptr)));
std::vector<mojom::ActivityIconPtr> icons;
icons.emplace_back(mojom::ActivityIcon::New(
mojom::ActivityName::New("p2", "a2"), 1, 1, std::vector<uint8_t>(4),
mojom::RawIconPngData::New()));
icons.emplace_back(mojom::ActivityIcon::New(
mojom::ActivityName::New("p3", "a3"), 1, 1, std::vector<uint8_t>(4),
mojom::RawIconPngData::New()));
// Call OnIconsReady() and check that the cache is properly updated.
loader.OnIconsReadyForTesting(
std::move(activity_to_icons),
base::BindOnce(&ActivityIconLoaderOnIconsReadyTest::OnIconsReady,
weak_ptr_factory_.GetWeakPtr()),
std::move(icons));
WaitForIconReady();
}
} // namespace } // namespace
} // namespace internal } // namespace internal
} // namespace arc } // namespace arc
// Copyright 2020 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 COMPONENTS_ARC_INTENT_HELPER_ADAPTIVE_ICON_DELEGATE_H_
#define COMPONENTS_ARC_INTENT_HELPER_ADAPTIVE_ICON_DELEGATE_H_
#include <vector>
#include "base/callback.h"
#include "components/arc/mojom/intent_helper.mojom.h"
#include "ui/gfx/image/image_skia.h"
namespace arc {
class AdaptiveIconDelegate {
public:
using AdaptiveIconDelegateCallback = base::OnceCallback<void(
const std::vector<gfx::ImageSkia>& adaptive_icons)>;
virtual ~AdaptiveIconDelegate() = default;
// Generates adaptive icons from the |icons| and calls |callback|.
virtual void GenerateAdaptiveIcons(
const std::vector<mojom::ActivityIconPtr>& icons,
AdaptiveIconDelegateCallback callback) = 0;
};
} // namespace arc
#endif // COMPONENTS_ARC_INTENT_HELPER_ADAPTIVE_ICON_DELEGATE_H_
...@@ -318,6 +318,11 @@ bool ArcIntentHelperBridge::ShouldChromeHandleUrl(const GURL& url) { ...@@ -318,6 +318,11 @@ bool ArcIntentHelperBridge::ShouldChromeHandleUrl(const GURL& url) {
return true; return true;
} }
void ArcIntentHelperBridge::SetAdaptiveIconDelegate(
AdaptiveIconDelegate* delegate) {
icon_loader_.SetAdaptiveIconDelegate(delegate);
}
void ArcIntentHelperBridge::AddObserver(ArcIntentHelperObserver* observer) { void ArcIntentHelperBridge::AddObserver(ArcIntentHelperObserver* observer) {
observer_list_.AddObserver(observer); observer_list_.AddObserver(observer);
} }
......
...@@ -29,6 +29,7 @@ class BrowserContext; ...@@ -29,6 +29,7 @@ class BrowserContext;
namespace arc { namespace arc {
class AdaptiveIconDelegate;
class ArcBridgeService; class ArcBridgeService;
class ControlCameraAppDelegate; class ControlCameraAppDelegate;
class FactoryResetDelegate; class FactoryResetDelegate;
...@@ -61,6 +62,8 @@ class ArcIntentHelperBridge : public KeyedService, ...@@ -61,6 +62,8 @@ class ArcIntentHelperBridge : public KeyedService,
ArcBridgeService* bridge_service); ArcBridgeService* bridge_service);
~ArcIntentHelperBridge() override; ~ArcIntentHelperBridge() override;
void SetAdaptiveIconDelegate(AdaptiveIconDelegate* delegate);
void AddObserver(ArcIntentHelperObserver* observer); void AddObserver(ArcIntentHelperObserver* observer);
void RemoveObserver(ArcIntentHelperObserver* observer); void RemoveObserver(ArcIntentHelperObserver* observer);
bool HasObserver(ArcIntentHelperObserver* observer) const; bool HasObserver(ArcIntentHelperObserver* observer) const;
......
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