blob: 6263b368eaf1b452c6eb6d4307e1bfeb946a375a [file] [log] [blame]
// 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 "ash/public/cpp/holding_space/holding_space_item.h"
#include "ash/public/cpp/holding_space/holding_space_image.h"
#include "ash/public/cpp/holding_space/holding_space_util.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/json/values_util.h"
#include "base/memory/ptr_util.h"
#include "base/strings/strcat.h"
#include "base/unguessable_token.h"
#include "ui/base/l10n/l10n_util.h"
namespace ash {
namespace {
// Used to indicate which version of serialization is being used. When
// intentionally breaking backwards compatibility, increment this value and
// perform any necessary conversions in `Deserialize()`.
constexpr int kVersion = 1;
// Preference paths.
// NOTE: As these paths are written to preferences, changes must ensure
// backwards compatibility. When intentionally breaking backwards compatibility,
// increment `kVersion` and perform any needed conversions in `Deserialize()`.
constexpr char kFilePathPath[] = "filePath";
constexpr char kIdPath[] = "id";
constexpr char kTypePath[] = "type";
constexpr char kVersionPath[] = "version";
} // namespace
HoldingSpaceItem::~HoldingSpaceItem() {
deletion_callback_list_.Notify();
}
bool HoldingSpaceItem::operator==(const HoldingSpaceItem& rhs) const {
return type_ == rhs.type_ && id_ == rhs.id_ && file_path_ == rhs.file_path_ &&
file_system_url_ == rhs.file_system_url_ && text_ == rhs.text_ &&
secondary_text_ == rhs.secondary_text_ &&
secondary_text_color_ == rhs.secondary_text_color_ &&
*image_ == *rhs.image_ && progress_ == rhs.progress_ &&
in_progress_commands_ == rhs.in_progress_commands_;
}
// static
std::unique_ptr<HoldingSpaceItem> HoldingSpaceItem::CreateFileBackedItem(
Type type,
const base::FilePath& file_path,
const GURL& file_system_url,
ImageResolver image_resolver) {
return CreateFileBackedItem(type, file_path, file_system_url,
HoldingSpaceProgress(),
std::move(image_resolver));
}
// static
std::unique_ptr<HoldingSpaceItem> HoldingSpaceItem::CreateFileBackedItem(
Type type,
const base::FilePath& file_path,
const GURL& file_system_url,
const HoldingSpaceProgress& progress,
ImageResolver image_resolver) {
DCHECK(!file_system_url.is_empty());
// Note: std::make_unique does not work with private constructors.
return base::WrapUnique(new HoldingSpaceItem(
type, /*id=*/base::UnguessableToken::Create().ToString(), file_path,
file_system_url, std::move(image_resolver).Run(type, file_path),
progress));
}
// static
bool HoldingSpaceItem::IsDownload(HoldingSpaceItem::Type type) {
switch (type) {
case Type::kArcDownload:
case Type::kDownload:
case Type::kLacrosDownload:
return true;
case Type::kDiagnosticsLog:
case Type::kNearbyShare:
case Type::kPinnedFile:
case Type::kPrintedPdf:
case Type::kScan:
case Type::kScreenRecording:
case Type::kScreenshot:
case Type::kPhoneHubCameraRoll:
return false;
}
}
// static
// NOTE: This method must remain in sync with `Serialize()`. If multiple
// serialization versions are supported, care must be taken to handle each.
std::unique_ptr<HoldingSpaceItem> HoldingSpaceItem::Deserialize(
const base::DictionaryValue& dict,
ImageResolver image_resolver) {
const absl::optional<int> version = dict.FindIntPath(kVersionPath);
DCHECK(version.has_value() && version.value() == kVersion);
const Type type = static_cast<Type>(dict.FindIntPath(kTypePath).value());
const base::FilePath file_path = DeserializeFilePath(dict);
// NOTE: `std::make_unique` does not work with private constructors.
return base::WrapUnique(new HoldingSpaceItem(
type, DeserializeId(dict), file_path,
/*file_system_url=*/GURL(),
std::move(image_resolver).Run(type, file_path), HoldingSpaceProgress()));
}
// static
// NOTE: This method must remain in sync with `Serialize()`. If multiple
// serialization versions are supported, care must be taken to handle each.
const std::string& HoldingSpaceItem::DeserializeId(
const base::DictionaryValue& dict) {
const absl::optional<int> version = dict.FindIntPath(kVersionPath);
DCHECK(version.has_value() && version.value() == kVersion);
const std::string* id = dict.FindStringPath(kIdPath);
DCHECK(id);
return *id;
}
// static
// NOTE: This method must remain in sync with `Serialize()`. If multiple
// serialization versions are supported, care must be taken to handle each.
base::FilePath HoldingSpaceItem::DeserializeFilePath(
const base::DictionaryValue& dict) {
const absl::optional<int> version = dict.FindIntPath(kVersionPath);
DCHECK(version.has_value() && version.value() == kVersion);
const absl::optional<base::FilePath> file_path =
base::ValueToFilePath(dict.FindPath(kFilePathPath));
DCHECK(file_path.has_value());
return file_path.value();
}
// NOTE: This method must remain in sync with `Deserialize()`. The
// return value will be written to preferences so this implementation must
// maintain backwards compatibility so long as `kVersion` remains unchanged.
base::DictionaryValue HoldingSpaceItem::Serialize() const {
base::DictionaryValue dict;
dict.SetIntPath(kVersionPath, kVersion);
dict.SetIntPath(kTypePath, static_cast<int>(type_));
dict.SetStringPath(kIdPath, id_);
dict.SetPath(kFilePathPath, base::FilePathToValue(file_path_));
return dict;
}
base::CallbackListSubscription HoldingSpaceItem::AddDeletionCallback(
base::RepeatingClosureList::CallbackType callback) const {
return deletion_callback_list_.Add(std::move(callback));
}
bool HoldingSpaceItem::IsInitialized() const {
return !file_system_url_.is_empty();
}
void HoldingSpaceItem::Initialize(const GURL& file_system_url) {
DCHECK(!IsInitialized());
DCHECK(!file_system_url.is_empty());
file_system_url_ = file_system_url;
}
bool HoldingSpaceItem::SetBackingFile(const base::FilePath& file_path,
const GURL& file_system_url) {
if (file_path_ == file_path && file_system_url_ == file_system_url)
return false;
file_path_ = file_path;
file_system_url_ = file_system_url;
image_->UpdateBackingFilePath(file_path);
return true;
}
std::u16string HoldingSpaceItem::GetText() const {
return text_.value_or(file_path_.BaseName().LossyDisplayName());
}
bool HoldingSpaceItem::SetText(const absl::optional<std::u16string>& text) {
if (text_ == text)
return false;
text_ = text;
return true;
}
bool HoldingSpaceItem::SetSecondaryText(
const absl::optional<std::u16string>& secondary_text) {
if (secondary_text_ == secondary_text)
return false;
secondary_text_ = secondary_text;
return true;
}
bool HoldingSpaceItem::SetSecondaryTextColor(
const absl::optional<cros_styles::ColorName>& secondary_text_color) {
if (secondary_text_color_ == secondary_text_color)
return false;
secondary_text_color_ = secondary_text_color;
return true;
}
std::u16string HoldingSpaceItem::GetAccessibleName() const {
if (accessible_name_)
return accessible_name_.value();
const std::u16string text = GetText();
if (!secondary_text_)
return text;
return l10n_util::GetStringFUTF16(
IDS_ASH_HOLDING_SPACE_ITEM_A11Y_NAME_AND_TOOLTIP, text,
secondary_text_.value());
}
bool HoldingSpaceItem::SetAccessibleName(
const absl::optional<std::u16string>& accessible_name) {
if (accessible_name_ == accessible_name)
return false;
accessible_name_ = accessible_name;
return true;
}
bool HoldingSpaceItem::SetProgress(const HoldingSpaceProgress& progress) {
// NOTE: Progress can only be updated for in progress items.
if (progress_ == progress || progress_.IsComplete())
return false;
progress_ = progress;
if (progress_.IsComplete())
in_progress_commands_.clear();
return true;
}
bool HoldingSpaceItem::SetInProgressCommands(
std::set<HoldingSpaceCommandId> in_progress_commands) {
DCHECK(std::all_of(in_progress_commands.begin(), in_progress_commands.end(),
&holding_space_util::IsInProgressCommand));
if (progress_.IsComplete() || in_progress_commands_ == in_progress_commands)
return false;
in_progress_commands_ = in_progress_commands;
return true;
}
void HoldingSpaceItem::InvalidateImage() {
if (image_)
image_->Invalidate();
}
bool HoldingSpaceItem::IsScreenCapture() const {
switch (type_) {
case Type::kScreenRecording:
case Type::kScreenshot:
return true;
case Type::kArcDownload:
case Type::kDiagnosticsLog:
case Type::kDownload:
case Type::kLacrosDownload:
case Type::kNearbyShare:
case Type::kPinnedFile:
case Type::kPrintedPdf:
case Type::kScan:
case Type::kPhoneHubCameraRoll:
return false;
}
}
HoldingSpaceItem::HoldingSpaceItem(Type type,
const std::string& id,
const base::FilePath& file_path,
const GURL& file_system_url,
std::unique_ptr<HoldingSpaceImage> image,
const HoldingSpaceProgress& progress)
: type_(type),
id_(id),
file_path_(file_path),
file_system_url_(file_system_url),
image_(std::move(image)),
progress_(progress) {}
} // namespace ash