1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ash/public/cpp/holding_space/holding_space_item.h"
6 
7 #include "ash/public/cpp/holding_space/holding_space_image.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/strings/strcat.h"
10 #include "base/util/values/values_util.h"
11 
12 namespace ash {
13 
14 namespace {
15 
16 // Used to indicate which version of serialization is being used. When
17 // intentionally breaking backwards compatibility, increment this value and
18 // perform any necessary conversions in `Deserialize()`.
19 constexpr int kVersion = 1;
20 
21 // Preference paths.
22 // NOTE: As these paths are written to preferences, changes must ensure
23 // backwards compatibility. When intentionally breaking backwards compatibility,
24 // increment `kVersion` and perform any needed conversions in `Deserialize()`.
25 constexpr char kFilePathPath[] = "filePath";
26 constexpr char kIdPath[] = "id";
27 constexpr char kTypePath[] = "type";
28 constexpr char kVersionPath[] = "version";
29 
TypeToString(HoldingSpaceItem::Type type)30 std::string TypeToString(HoldingSpaceItem::Type type) {
31   switch (type) {
32     case HoldingSpaceItem::Type::kPinnedFile:
33       return "pinned_file";
34     case HoldingSpaceItem::Type::kDownload:
35       return "download";
36     case HoldingSpaceItem::Type::kScreenshot:
37       return "screenshot";
38     case HoldingSpaceItem::Type::kNearbyShare:
39       return "nearby_share";
40     case HoldingSpaceItem::Type::kScreenRecording:
41       return "screen_recording";
42   }
43 }
44 
45 }  // namespace
46 
47 HoldingSpaceItem::~HoldingSpaceItem() = default;
48 
operator ==(const HoldingSpaceItem & rhs) const49 bool HoldingSpaceItem::operator==(const HoldingSpaceItem& rhs) const {
50   return type_ == rhs.type_ && id_ == rhs.id_ && file_path_ == rhs.file_path_ &&
51          file_system_url_ == rhs.file_system_url_ && text_ == rhs.text_ &&
52          *image_ == *rhs.image_;
53 }
54 
55 // static
GetFileBackedItemId(Type type,const base::FilePath & file_path)56 std::string HoldingSpaceItem::GetFileBackedItemId(
57     Type type,
58     const base::FilePath& file_path) {
59   return base::StrCat({TypeToString(type), ":", file_path.value()});
60 }
61 
62 // static
CreateFileBackedItem(Type type,const base::FilePath & file_path,const GURL & file_system_url,std::unique_ptr<HoldingSpaceImage> image)63 std::unique_ptr<HoldingSpaceItem> HoldingSpaceItem::CreateFileBackedItem(
64     Type type,
65     const base::FilePath& file_path,
66     const GURL& file_system_url,
67     std::unique_ptr<HoldingSpaceImage> image) {
68   DCHECK(!file_system_url.is_empty());
69 
70   // Note: std::make_unique does not work with private constructors.
71   return base::WrapUnique(new HoldingSpaceItem(
72       type, GetFileBackedItemId(type, file_path), file_path, file_system_url,
73       file_path.BaseName().LossyDisplayName(), std::move(image)));
74 }
75 
76 // static
77 // NOTE: This method must remain in sync with `Serialize()`. If multiple
78 // serialization versions are supported, care must be taken to handle each.
Deserialize(const base::DictionaryValue & dict,ImageResolver image_resolver)79 std::unique_ptr<HoldingSpaceItem> HoldingSpaceItem::Deserialize(
80     const base::DictionaryValue& dict,
81     ImageResolver image_resolver) {
82   const base::Optional<int> version = dict.FindIntPath(kVersionPath);
83   DCHECK(version.has_value() && version.value() == kVersion);
84 
85   const Type type = static_cast<Type>(dict.FindIntPath(kTypePath).value());
86   const base::FilePath file_path = DeserializeFilePath(dict);
87 
88   // NOTE: `std::make_unique` does not work with private constructors.
89   return base::WrapUnique(new HoldingSpaceItem(
90       type, DeserializeId(dict), file_path,
91       /*file_system_url=*/GURL(), file_path.BaseName().LossyDisplayName(),
92       std::move(image_resolver).Run(type, file_path)));
93 }
94 
95 // static
96 // NOTE: This method must remain in sync with `Serialize()`. If multiple
97 // serialization versions are supported, care must be taken to handle each.
DeserializeId(const base::DictionaryValue & dict)98 const std::string& HoldingSpaceItem::DeserializeId(
99     const base::DictionaryValue& dict) {
100   const base::Optional<int> version = dict.FindIntPath(kVersionPath);
101   DCHECK(version.has_value() && version.value() == kVersion);
102 
103   const std::string* id = dict.FindStringPath(kIdPath);
104   DCHECK(id);
105 
106   return *id;
107 }
108 
109 // static
110 // NOTE: This method must remain in sync with `Serialize()`. If multiple
111 // serialization versions are supported, care must be taken to handle each.
DeserializeFilePath(const base::DictionaryValue & dict)112 base::FilePath HoldingSpaceItem::DeserializeFilePath(
113     const base::DictionaryValue& dict) {
114   const base::Optional<int> version = dict.FindIntPath(kVersionPath);
115   DCHECK(version.has_value() && version.value() == kVersion);
116 
117   const base::Optional<base::FilePath> file_path =
118       util::ValueToFilePath(dict.FindPath(kFilePathPath));
119   DCHECK(file_path.has_value());
120 
121   return file_path.value();
122 }
123 
124 // NOTE: This method must remain in sync with `Deserialize()`. The
125 // return value will be written to preferences so this implementation must
126 // maintain backwards compatibility so long as `kVersion` remains unchanged.
Serialize() const127 base::DictionaryValue HoldingSpaceItem::Serialize() const {
128   base::DictionaryValue dict;
129   dict.SetIntPath(kVersionPath, kVersion);
130   dict.SetIntPath(kTypePath, static_cast<int>(type_));
131   dict.SetStringPath(kIdPath, id_);
132   dict.SetPath(kFilePathPath, util::FilePathToValue(file_path_));
133   return dict;
134 }
135 
HoldingSpaceItem(Type type,const std::string & id,const base::FilePath & file_path,const GURL & file_system_url,const base::string16 & text,std::unique_ptr<HoldingSpaceImage> image)136 HoldingSpaceItem::HoldingSpaceItem(Type type,
137                                    const std::string& id,
138                                    const base::FilePath& file_path,
139                                    const GURL& file_system_url,
140                                    const base::string16& text,
141                                    std::unique_ptr<HoldingSpaceImage> image)
142     : type_(type),
143       id_(id),
144       file_path_(file_path),
145       file_system_url_(file_system_url),
146       text_(text),
147       image_(std::move(image)) {}
148 
IsFinalized() const149 bool HoldingSpaceItem::IsFinalized() const {
150   return !file_system_url_.is_empty();
151 }
152 
Finalize(const GURL & file_system_url)153 void HoldingSpaceItem::Finalize(const GURL& file_system_url) {
154   DCHECK(!IsFinalized());
155   DCHECK(!file_system_url.is_empty());
156   file_system_url_ = file_system_url;
157 }
158 
159 }  // namespace ash
160