Commit a3b50b40 authored by Jit Yao Yap's avatar Jit Yao Yap Committed by Commit Bot

Add placeholder icon for Remote Apps

When a Remote App's icon has not been downloaded, or the icon download
has failed, a placeholder icon will be used. The placeholder icon is
a gray circle with the app's name's first letter drawn over it.

Bug: 1101208
Change-Id: I2c35e5dead98783004ce01aa00e87d6a98d8dca0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2359074
Commit-Queue: Jit Yao Yap <jityao@google.com>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarNancy Wang <nancylingwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#800074}
parent a4d4ded3
......@@ -83,18 +83,24 @@ void RemoteApps::LoadIcon(const std::string& app_id,
int32_t size_hint_in_dip,
bool allow_placeholder_icon,
LoadIconCallback callback) {
// TODO(crbug.com/1083331): Handle IconType::kStandard.
DCHECK(icon_type != mojom::IconType::kCompressed)
<< "Remote app should not be shown in management";
mojom::IconValuePtr icon = mojom::IconValue::New();
bool is_placeholder_icon = false;
gfx::ImageSkia icon_image = delegate_->GetIcon(app_id);
if (icon_image.isNull() && allow_placeholder_icon) {
is_placeholder_icon = true;
icon_image = delegate_->GetPlaceholderIcon(app_id, size_hint_in_dip);
}
if (!icon_image.isNull()) {
icon->icon_type = icon_type;
icon->uncompressed = icon_image;
icon->is_placeholder_icon = is_placeholder_icon;
IconEffects icon_effects = (icon_type == mojom::IconType::kStandard)
? IconEffects::kCrOsStandardIcon
: IconEffects::kResizeAndPad;
icon->uncompressed = icon_image;
apps::ApplyIconEffects(icon_effects, size_hint_in_dip, &icon->uncompressed);
}
......
......@@ -40,6 +40,9 @@ class RemoteApps : public apps::PublisherBase {
virtual gfx::ImageSkia GetIcon(const std::string& id) = 0;
virtual gfx::ImageSkia GetPlaceholderIcon(const std::string& id,
int32_t size_hint_in_dip) = 0;
virtual void LaunchApp(const std::string& id) = 0;
virtual apps::mojom::MenuItemsPtr GetMenuModel(const std::string& id) = 0;
......
......@@ -9,6 +9,9 @@
#include "ash/public/cpp/app_menu_constants.h"
#include "ash/public/cpp/image_downloader.h"
#include "base/bind.h"
#include "base/i18n/rtl.h"
#include "base/strings/utf_string_conversions.h"
#include "cc/paint/paint_flags.h"
#include "chrome/browser/apps/app_service/menu_util.h"
#include "chrome/browser/chromeos/remote_apps/remote_apps_impl.h"
#include "chrome/browser/profiles/profile.h"
......@@ -19,6 +22,12 @@
#include "chrome/grit/generated_resources.h"
#include "components/services/app_service/public/cpp/app_update.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/canvas_image_source.h"
#include "ui/gfx/image/image_skia.h"
namespace chromeos {
......@@ -41,6 +50,55 @@ class ImageDownloaderImpl : public RemoteAppsManager::ImageDownloader {
}
};
// Placeholder icon which shows the first letter of the app's name on top of a
// gray circle.
class RemoteAppsPlaceholderIcon : public gfx::CanvasImageSource {
public:
RemoteAppsPlaceholderIcon(const std::string& name, int32_t size)
: gfx::CanvasImageSource(gfx::Size(size, size)) {
base::string16 sanitized_name = base::UTF8ToUTF16(std::string(name));
base::i18n::UnadjustStringForLocaleDirection(&sanitized_name);
letter_ = sanitized_name.substr(0, 1);
if (size <= 16)
font_style_ = ui::ResourceBundle::SmallFont;
else if (size <= 32)
font_style_ = ui::ResourceBundle::MediumFont;
else
font_style_ = ui::ResourceBundle::LargeFont;
}
RemoteAppsPlaceholderIcon(const RemoteAppsPlaceholderIcon&) = delete;
RemoteAppsPlaceholderIcon& operator=(const RemoteAppsPlaceholderIcon&) =
delete;
~RemoteAppsPlaceholderIcon() override = default;
private:
// gfx::CanvasImageSource:
void Draw(gfx::Canvas* canvas) override {
const gfx::Size& icon_size = size();
float width = static_cast<float>(icon_size.width());
float height = static_cast<float>(icon_size.height());
// Draw gray circle.
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setColor(SK_ColorGRAY);
flags.setStyle(cc::PaintFlags::kFill_Style);
canvas->DrawCircle(gfx::PointF(width / 2, height / 2), width / 2, flags);
// Draw the letter on top.
canvas->DrawStringRectWithFlags(
letter_,
ui::ResourceBundle::GetSharedInstance().GetFontList(font_style_),
SK_ColorWHITE, gfx::Rect(icon_size.width(), icon_size.height()),
gfx::Canvas::TEXT_ALIGN_CENTER);
}
// The first letter of the app's name.
base::string16 letter_;
ui::ResourceBundle::FontStyle font_style_ = ui::ResourceBundle::MediumFont;
};
} // namespace
RemoteAppsManager::RemoteAppsManager(Profile* profile)
......@@ -161,6 +219,18 @@ gfx::ImageSkia RemoteAppsManager::GetIcon(const std::string& id) {
return model_->GetAppInfo(id).icon;
}
gfx::ImageSkia RemoteAppsManager::GetPlaceholderIcon(const std::string& id,
int32_t size_hint_in_dip) {
if (!model_->HasApp(id))
return gfx::ImageSkia();
gfx::ImageSkia icon(std::make_unique<RemoteAppsPlaceholderIcon>(
model_->GetAppInfo(id).name, size_hint_in_dip),
gfx::Size(size_hint_in_dip, size_hint_in_dip));
icon.EnsureRepsForSupportedScales();
return icon;
}
apps::mojom::MenuItemsPtr RemoteAppsManager::GetMenuModel(
const std::string& id) {
apps::mojom::MenuItemsPtr menu_items = apps::mojom::MenuItems::New();
......
......@@ -123,6 +123,8 @@ class RemoteAppsManager : public KeyedService,
const std::map<std::string, RemoteAppsModel::AppInfo>& GetApps() override;
void LaunchApp(const std::string& id) override;
gfx::ImageSkia GetIcon(const std::string& id) override;
gfx::ImageSkia GetPlaceholderIcon(const std::string& id,
int32_t size_hint_in_dip) override;
apps::mojom::MenuItemsPtr GetMenuModel(const std::string& id) override;
// app_list::AppListSyncableService::Observer:
......
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