Commit 83df6593 authored by Nancy Wang's avatar Nancy Wang Committed by Chromium LUCI CQ

Add construct function to convert from base::Value to RestoreData.

This is the preparing for the full restore file reading function. Add
the construct function for RestoreData to convert the JSON format to
the RestoreData.

Add the unit tests to verify the convert function:
RestoreData -> base::Value -> RestoreData.

BUG=1146900

Change-Id: I54133e83e9b7abce62c5812cc5e87941e770f958
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2591987Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Commit-Queue: Nancy Wang <nancylingwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#837465}
parent 336ce7f7
...@@ -26,6 +26,7 @@ component("full_restore") { ...@@ -26,6 +26,7 @@ component("full_restore") {
public_deps = [ public_deps = [
"//ash/public/cpp", "//ash/public/cpp",
"//base", "//base",
"//components/services/app_service/public/cpp:intents",
"//components/services/app_service/public/mojom", "//components/services/app_service/public/mojom",
"//ui/aura", "//ui/aura",
] ]
......
...@@ -2,11 +2,14 @@ ...@@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <utility>
#include "components/full_restore/app_restore_data.h" #include "components/full_restore/app_restore_data.h"
#include <utility>
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "components/full_restore/app_launch_info.h" #include "components/full_restore/app_launch_info.h"
#include "components/services/app_service/public/cpp/intent_util.h"
namespace full_restore { namespace full_restore {
...@@ -18,13 +21,6 @@ const char kDispositionKey[] = "disposition"; ...@@ -18,13 +21,6 @@ const char kDispositionKey[] = "disposition";
const char kDisplayIdKey[] = "display_id"; const char kDisplayIdKey[] = "display_id";
const char kUrlKey[] = "url"; const char kUrlKey[] = "url";
const char kIntentKey[] = "intent"; const char kIntentKey[] = "intent";
const char kActionKey[] = "action";
const char kMimeTypeKey[] = "mime_type";
const char kFileUrlsKey[] = "file_urls";
const char kActivityNameKey[] = "activity_name";
const char kDriveShareUrlKey[] = "drive_share_url";
const char kShareTextKey[] = "share_text";
const char kShareTitleKey[] = "share_title";
const char kFilePathsKey[] = "file_paths"; const char kFilePathsKey[] = "file_paths";
const char kActivationIndexKey[] = "index"; const char kActivationIndexKey[] = "index";
const char kDeskIdKey[] = "desk_id"; const char kDeskIdKey[] = "desk_id";
...@@ -32,74 +28,114 @@ const char kRestoredBoundsKey[] = "restored_bounds"; ...@@ -32,74 +28,114 @@ const char kRestoredBoundsKey[] = "restored_bounds";
const char kcurrentBoundsKey[] = "current_bounds"; const char kcurrentBoundsKey[] = "current_bounds";
const char kWindowStateTypeKey[] = "window_state_type"; const char kWindowStateTypeKey[] = "window_state_type";
// Converts |intent| to base::Value, e.g.: // Converts |rect| to base::Value, e.g. { 0, 100, 200, 300 }.
// { base::Value ConvertRectToValue(const gfx::Rect& rect) {
// "action": "xx", base::Value rect_list(base::Value::Type::LIST);
// "url": "abc.com", rect_list.Append(base::Value(rect.x()));
// "mime_type": "text/plain", rect_list.Append(base::Value(rect.y()));
// "file_urls": "/abc, /a", rect_list.Append(base::Value(rect.width()));
// "activity_name": "yy", rect_list.Append(base::Value(rect.height()));
// "drive_share_url": "aa.com", return rect_list;
// "share_text": "text", }
// "share_title": "title",
// }
base::Value ConvertIntentToValue(const apps::mojom::IntentPtr& intent) {
DCHECK(intent);
base::Value intent_value(base::Value::Type::DICTIONARY);
if (intent->action.has_value() && !intent->action.value().empty())
intent_value.SetStringKey(kActionKey, intent->action.value());
if (intent->url.has_value()) {
DCHECK(intent->url.value().is_valid());
intent_value.SetStringKey(kUrlKey, intent->url.value().spec());
}
if (intent->mime_type.has_value() && !intent->mime_type.value().empty()) // Gets int value from base::DictionaryValue, e.g. { "key": 100 } returns 100.
intent_value.SetStringKey(kMimeTypeKey, intent->mime_type.value()); base::Optional<int32_t> GetIntValueFromDict(const base::DictionaryValue& dict,
const std::string& key_name) {
return dict.HasKey(key_name) ? dict.FindIntKey(key_name) : base::nullopt;
}
if (intent->file_urls.has_value() && !intent->file_urls.value().empty()) { // Gets display id from base::DictionaryValue, e.g. { "display_id": "22000000" }
base::Value file_urls_list(base::Value::Type::LIST); // returns 22000000.
for (auto& url : intent->file_urls.value()) { base::Optional<int64_t> GetDisplayIdFromDict(
DCHECK(intent->drive_share_url.value().is_valid()); const base::DictionaryValue& dict) {
file_urls_list.Append(base::Value(url.spec())); if (!dict.HasKey(kDisplayIdKey))
} return base::nullopt;
intent_value.SetKey(kFileUrlsKey, std::move(file_urls_list));
const std::string* display_id_str = dict.FindStringKey(kDisplayIdKey);
int64_t display_id_value;
if (display_id_str &&
base::StringToInt64(*display_id_str, &display_id_value)) {
return display_id_value;
} }
if (intent->activity_name.has_value() && return base::nullopt;
!intent->activity_name.value().empty()) { }
intent_value.SetStringKey(kActivityNameKey, intent->activity_name.value());
}
if (intent->drive_share_url.has_value()) { // Gets std::vector<base::FilePath> from base::DictionaryValue, e.g.
DCHECK(intent->drive_share_url.value().is_valid()); // {"file_paths": { "aa.cc", "bb.h", ... }} returns
intent_value.SetStringKey(kDriveShareUrlKey, // std::vector<base::FilePath>{"aa.cc", "bb.h", ...}.
intent->drive_share_url.value().spec()); base::Optional<std::vector<base::FilePath>> GetFilePathsFromDict(
const base::DictionaryValue& dict) {
if (!dict.HasKey(kFilePathsKey))
return base::nullopt;
const base::Value* file_paths_value = dict.FindListKey(kFilePathsKey);
if (!file_paths_value || !file_paths_value->is_list() ||
file_paths_value->GetList().empty())
return base::nullopt;
std::vector<base::FilePath> file_paths;
for (const auto& item : file_paths_value->GetList()) {
if (item.GetString().empty())
continue;
file_paths.push_back(base::FilePath(item.GetString()));
} }
if (intent->share_text.has_value() && !intent->share_text.value().empty()) return file_paths;
intent_value.SetStringKey(kShareTextKey, intent->share_text.value()); }
if (intent->share_title.has_value() && !intent->share_title.value().empty()) // Gets gfx::Rect from base::Value, e.g. { 0, 100, 200, 300 } returns
intent_value.SetStringKey(kShareTitleKey, intent->share_title.value()); // gfx::Rect(0, 100, 200, 300).
base::Optional<gfx::Rect> GetBoundsRectFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
if (!dict.HasKey(key_name))
return base::nullopt;
return intent_value; const base::Value* rect_value = dict.FindListKey(key_name);
} if (!rect_value || !rect_value->is_list() || rect_value->GetList().empty())
return base::nullopt;
// Converts |rect| to base::Value, e.g. { 0, 100, 200, 300 }. std::vector<int> rect;
base::Value ConvertRectToValue(const gfx::Rect& rect) { for (const auto& item : rect_value->GetList())
base::Value rect_list(base::Value::Type::LIST); rect.push_back(item.GetInt());
rect_list.Append(base::Value(rect.x()));
rect_list.Append(base::Value(rect.y())); if (rect.size() != 4)
rect_list.Append(base::Value(rect.width())); return base::nullopt;
rect_list.Append(base::Value(rect.height()));
return rect_list; return gfx::Rect(rect[0], rect[1], rect[2], rect[3]);
} }
} // namespace } // namespace
AppRestoreData::AppRestoreData() = default; AppRestoreData::AppRestoreData() = default;
AppRestoreData::AppRestoreData(base::Value&& value) {
base::DictionaryValue* data_dict = nullptr;
if (!value.is_dict() || !value.GetAsDictionary(&data_dict) || !data_dict) {
DVLOG(0) << "Fail to parse app restore data. "
<< "Cannot find the app restore data dict.";
return;
}
event_flag = GetIntValueFromDict(*data_dict, kEventFlagKey);
container = GetIntValueFromDict(*data_dict, kContainerKey);
disposition = GetIntValueFromDict(*data_dict, kDispositionKey);
display_id = GetDisplayIdFromDict(*data_dict);
url = apps_util::GetGurlValueFromDict(*data_dict, kUrlKey);
file_paths = GetFilePathsFromDict(*data_dict);
activation_index = GetIntValueFromDict(*data_dict, kActivationIndexKey);
desk_id = GetIntValueFromDict(*data_dict, kDeskIdKey);
restored_bounds = GetBoundsRectFromDict(*data_dict, kRestoredBoundsKey);
current_bounds = GetBoundsRectFromDict(*data_dict, kcurrentBoundsKey);
window_state_type = GetIntValueFromDict(*data_dict, kWindowStateTypeKey);
if (data_dict->HasKey(kIntentKey)) {
intent = apps_util::ConvertValueToIntent(
std::move(*data_dict->FindDictKey(kIntentKey)));
}
}
AppRestoreData::~AppRestoreData() = default; AppRestoreData::~AppRestoreData() = default;
base::Value AppRestoreData::ConvertToValue() const { base::Value AppRestoreData::ConvertToValue() const {
...@@ -122,8 +158,10 @@ base::Value AppRestoreData::ConvertToValue() const { ...@@ -122,8 +158,10 @@ base::Value AppRestoreData::ConvertToValue() const {
if (url.has_value()) if (url.has_value())
launch_info_dict.SetStringKey(kUrlKey, url.value().spec()); launch_info_dict.SetStringKey(kUrlKey, url.value().spec());
if (intent.has_value() && intent.value()) if (intent.has_value() && intent.value()) {
launch_info_dict.SetKey(kIntentKey, ConvertIntentToValue(intent.value())); launch_info_dict.SetKey(kIntentKey,
apps_util::ConvertIntentToValue(intent.value()));
}
if (file_paths.has_value() && !file_paths.value().empty()) { if (file_paths.has_value() && !file_paths.value().empty()) {
base::Value file_paths_list(base::Value::Type::LIST); base::Value file_paths_list(base::Value::Type::LIST);
...@@ -148,8 +186,8 @@ base::Value AppRestoreData::ConvertToValue() const { ...@@ -148,8 +186,8 @@ base::Value AppRestoreData::ConvertToValue() const {
ConvertRectToValue(current_bounds.value())); ConvertRectToValue(current_bounds.value()));
} }
if (Window_state_type.has_value()) if (window_state_type.has_value())
launch_info_dict.SetIntKey(kWindowStateTypeKey, Window_state_type.value()); launch_info_dict.SetIntKey(kWindowStateTypeKey, window_state_type.value());
return launch_info_dict; return launch_info_dict;
} }
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace base {
class Value;
}
namespace full_restore { namespace full_restore {
struct AppLaunchInfo; struct AppLaunchInfo;
...@@ -23,6 +27,8 @@ struct AppLaunchInfo; ...@@ -23,6 +27,8 @@ struct AppLaunchInfo;
// written to the FullRestoreData file. // written to the FullRestoreData file.
struct COMPONENT_EXPORT(FULL_RESTORE) AppRestoreData { struct COMPONENT_EXPORT(FULL_RESTORE) AppRestoreData {
AppRestoreData(); AppRestoreData();
explicit AppRestoreData(base::Value&& value);
~AppRestoreData(); ~AppRestoreData();
AppRestoreData(const AppRestoreData&) = delete; AppRestoreData(const AppRestoreData&) = delete;
...@@ -61,7 +67,7 @@ struct COMPONENT_EXPORT(FULL_RESTORE) AppRestoreData { ...@@ -61,7 +67,7 @@ struct COMPONENT_EXPORT(FULL_RESTORE) AppRestoreData {
base::Optional<int32_t> desk_id; base::Optional<int32_t> desk_id;
base::Optional<gfx::Rect> restored_bounds; base::Optional<gfx::Rect> restored_bounds;
base::Optional<gfx::Rect> current_bounds; base::Optional<gfx::Rect> current_bounds;
base::Optional<int32_t> Window_state_type; base::Optional<int32_t> window_state_type;
}; };
} // namespace full_restore } // namespace full_restore
......
...@@ -2,37 +2,71 @@ ...@@ -2,37 +2,71 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <utility>
#include "components/full_restore/restore_data.h" #include "components/full_restore/restore_data.h"
#include <utility>
#include "base/strings/string_number_conversions.h"
#include "base/values.h" #include "base/values.h"
#include "components/full_restore/app_launch_info.h" #include "components/full_restore/app_launch_info.h"
namespace full_restore { namespace full_restore {
RestoreData::RestoreData() = default; RestoreData::RestoreData() = default;
RestoreData::RestoreData(std::unique_ptr<base::Value> restore_data_value) {
base::DictionaryValue* restore_data_dict = nullptr;
if (!restore_data_value || !restore_data_value->is_dict() ||
!restore_data_value->GetAsDictionary(&restore_data_dict) ||
!restore_data_dict) {
DVLOG(0) << "Fail to parse full restore data. "
<< "Cannot find the full restore data dict.";
return;
}
for (base::DictionaryValue::Iterator iter(*restore_data_dict);
!iter.IsAtEnd(); iter.Advance()) {
const std::string& app_id = iter.key();
base::Value* value = restore_data_dict->FindDictKey(app_id);
base::DictionaryValue* data_dict = nullptr;
if (!value || !value->is_dict() || !value->GetAsDictionary(&data_dict) ||
!data_dict) {
DVLOG(0) << "Fail to parse full restore data. "
<< "Cannot find the app restore data dict.";
continue;
}
for (base::DictionaryValue::Iterator data_iter(*data_dict);
!data_iter.IsAtEnd(); data_iter.Advance()) {
int id = 0;
if (!base::StringToInt(data_iter.key(), &id)) {
DVLOG(0) << "Fail to parse full restore data. "
<< "Cannot find the valid id.";
continue;
}
app_id_to_launch_list_[app_id][id] = std::make_unique<AppRestoreData>(
std::move(*data_dict->FindDictKey(data_iter.key())));
}
}
}
RestoreData::~RestoreData() = default; RestoreData::~RestoreData() = default;
base::Value RestoreData::ConvertToValue() const { base::Value RestoreData::ConvertToValue() const {
base::Value restore_data_list(base::Value::Type::LIST); base::Value restore_data_dict(base::Value::Type::DICTIONARY);
for (const auto& it : app_id_to_launch_list_) { for (const auto& it : app_id_to_launch_list_) {
if (it.second.empty()) if (it.second.empty())
continue; continue;
base::Value launch_list(base::Value::Type::LIST); base::Value info_dict(base::Value::Type::DICTIONARY);
for (const auto& data : it.second) { for (const auto& data : it.second) {
base::Value info_dict(base::Value::Type::DICTIONARY);
info_dict.SetKey(base::NumberToString(data.first), info_dict.SetKey(base::NumberToString(data.first),
data.second->ConvertToValue()); data.second->ConvertToValue());
launch_list.Append(std::move(info_dict));
} }
base::Value restore_data_dict(base::Value::Type::DICTIONARY); restore_data_dict.SetKey(it.first, std::move(info_dict));
restore_data_dict.SetKey(it.first, std::move(launch_list));
restore_data_list.Append(std::move(restore_data_dict));
} }
return restore_data_list; return restore_data_dict;
} }
void RestoreData::AddAppLaunchInfo( void RestoreData::AddAppLaunchInfo(
......
...@@ -36,6 +36,8 @@ class COMPONENT_EXPORT(FULL_RESTORE) RestoreData { ...@@ -36,6 +36,8 @@ class COMPONENT_EXPORT(FULL_RESTORE) RestoreData {
using AppIdToLaunchList = std::map<std::string, LaunchList>; using AppIdToLaunchList = std::map<std::string, LaunchList>;
RestoreData(); RestoreData();
explicit RestoreData(std::unique_ptr<base::Value> restore_data_value);
~RestoreData(); ~RestoreData();
RestoreData(const RestoreData&) = delete; RestoreData(const RestoreData&) = delete;
...@@ -77,7 +79,7 @@ class COMPONENT_EXPORT(FULL_RESTORE) RestoreData { ...@@ -77,7 +79,7 @@ class COMPONENT_EXPORT(FULL_RESTORE) RestoreData {
// Add |app_launch_info| to |app_id_to_launch_list_|. // Add |app_launch_info| to |app_id_to_launch_list_|.
void AddAppLaunchInfo(std::unique_ptr<AppLaunchInfo> app_launch_info); void AddAppLaunchInfo(std::unique_ptr<AppLaunchInfo> app_launch_info);
const AppIdToLaunchList& app_id_to_launch_list() { const AppIdToLaunchList& app_id_to_launch_list() const {
return app_id_to_launch_list_; return app_id_to_launch_list_;
} }
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include "components/full_restore/restore_data.h" #include "components/full_restore/restore_data.h"
#include <memory>
#include <utility>
#include "components/full_restore/app_launch_info.h" #include "components/full_restore/app_launch_info.h"
#include "components/full_restore/app_restore_data.h" #include "components/full_restore/app_restore_data.h"
#include "components/services/app_service/public/mojom/types.mojom.h" #include "components/services/app_service/public/mojom/types.mojom.h"
...@@ -56,6 +59,34 @@ class RestoreDataTest : public testing::Test { ...@@ -56,6 +59,34 @@ class RestoreDataTest : public testing::Test {
return intent; return intent;
} }
void AddAppLaunchInfos() {
std::unique_ptr<AppLaunchInfo> app_launch_info1 =
std::make_unique<AppLaunchInfo>(
kAppId1, kId1, apps::mojom::LaunchContainer::kLaunchContainerWindow,
WindowOpenDisposition::NEW_WINDOW, kDisplayId1,
std::vector<base::FilePath>{base::FilePath(kFilePath1),
base::FilePath(kFilePath2)},
CreateIntent(kIntentActionSend, kMimeType, kShareText1));
std::unique_ptr<AppLaunchInfo> app_launch_info2 =
std::make_unique<AppLaunchInfo>(
kAppId1, kId2, apps::mojom::LaunchContainer::kLaunchContainerTab,
WindowOpenDisposition::NEW_FOREGROUND_TAB, kDisplayId2,
std::vector<base::FilePath>{base::FilePath(kFilePath2)},
CreateIntent(kIntentActionView, kMimeType, kShareText2));
std::unique_ptr<AppLaunchInfo> app_launch_info3 =
std::make_unique<AppLaunchInfo>(
kAppId2, kId3, apps::mojom::LaunchContainer::kLaunchContainerNone,
WindowOpenDisposition::NEW_POPUP, kDisplayId2,
std::vector<base::FilePath>{base::FilePath(kFilePath1)},
CreateIntent(kIntentActionView, kMimeType, kShareText1));
restore_data().AddAppLaunchInfo(std::move(app_launch_info1));
restore_data().AddAppLaunchInfo(std::move(app_launch_info2));
restore_data().AddAppLaunchInfo(std::move(app_launch_info3));
}
void VerifyAppRestoreData(const std::unique_ptr<AppRestoreData>& data, void VerifyAppRestoreData(const std::unique_ptr<AppRestoreData>& data,
apps::mojom::LaunchContainer container, apps::mojom::LaunchContainer container,
WindowOpenDisposition disposition, WindowOpenDisposition disposition,
...@@ -82,12 +113,61 @@ class RestoreDataTest : public testing::Test { ...@@ -82,12 +113,61 @@ class RestoreDataTest : public testing::Test {
EXPECT_EQ(intent->share_text, data->intent.value()->share_text); EXPECT_EQ(intent->share_text, data->intent.value()->share_text);
} }
void VerifyRestoreData(const RestoreData& restore_data) {
EXPECT_EQ(2u, app_id_to_launch_list(restore_data).size());
// Verify for |kAppId1|
const auto launch_list_it1 =
app_id_to_launch_list(restore_data).find(kAppId1);
EXPECT_TRUE(launch_list_it1 != app_id_to_launch_list(restore_data).end());
EXPECT_EQ(2u, launch_list_it1->second.size());
const auto app_restore_data_it1 = launch_list_it1->second.find(kId1);
EXPECT_TRUE(app_restore_data_it1 != launch_list_it1->second.end());
VerifyAppRestoreData(
app_restore_data_it1->second,
apps::mojom::LaunchContainer::kLaunchContainerWindow,
WindowOpenDisposition::NEW_WINDOW, kDisplayId1,
std::vector<base::FilePath>{base::FilePath(kFilePath1),
base::FilePath(kFilePath2)},
CreateIntent(kIntentActionSend, kMimeType, kShareText1));
const auto app_restore_data_it2 = launch_list_it1->second.find(kId2);
EXPECT_TRUE(app_restore_data_it2 != launch_list_it1->second.end());
VerifyAppRestoreData(
app_restore_data_it2->second,
apps::mojom::LaunchContainer::kLaunchContainerTab,
WindowOpenDisposition::NEW_FOREGROUND_TAB, kDisplayId2,
std::vector<base::FilePath>{base::FilePath(kFilePath2)},
CreateIntent(kIntentActionView, kMimeType, kShareText2));
// Verify for |kAppId2|
const auto launch_list_it2 =
app_id_to_launch_list(restore_data).find(kAppId2);
EXPECT_TRUE(launch_list_it2 != app_id_to_launch_list(restore_data).end());
EXPECT_EQ(1u, launch_list_it2->second.size());
EXPECT_EQ(kId3, launch_list_it2->second.begin()->first);
VerifyAppRestoreData(
launch_list_it2->second.begin()->second,
apps::mojom::LaunchContainer::kLaunchContainerNone,
WindowOpenDisposition::NEW_POPUP, kDisplayId2,
std::vector<base::FilePath>{base::FilePath(kFilePath1)},
CreateIntent(kIntentActionView, kMimeType, kShareText1));
}
RestoreData& restore_data() { return restore_data_; } RestoreData& restore_data() { return restore_data_; }
const RestoreData::AppIdToLaunchList& app_id_to_launch_list() { const RestoreData::AppIdToLaunchList& app_id_to_launch_list() const {
return restore_data_.app_id_to_launch_list(); return restore_data_.app_id_to_launch_list();
} }
const RestoreData::AppIdToLaunchList& app_id_to_launch_list(
const RestoreData& restore_data) const {
return restore_data.app_id_to_launch_list();
}
private: private:
RestoreData restore_data_; RestoreData restore_data_;
}; };
...@@ -98,68 +178,29 @@ TEST_F(RestoreDataTest, AddNullAppLaunchInfo) { ...@@ -98,68 +178,29 @@ TEST_F(RestoreDataTest, AddNullAppLaunchInfo) {
} }
TEST_F(RestoreDataTest, AddAppLaunchInfos) { TEST_F(RestoreDataTest, AddAppLaunchInfos) {
std::unique_ptr<AppLaunchInfo> app_launch_info1 = AddAppLaunchInfos();
std::make_unique<AppLaunchInfo>(
kAppId1, kId1, apps::mojom::LaunchContainer::kLaunchContainerWindow, VerifyRestoreData(restore_data());
WindowOpenDisposition::NEW_WINDOW, kDisplayId1, }
std::vector<base::FilePath>{base::FilePath(kFilePath1),
base::FilePath(kFilePath2)}, TEST_F(RestoreDataTest, Convert) {
CreateIntent(kIntentActionSend, kMimeType, kShareText1)); AddAppLaunchInfos();
std::unique_ptr<base::Value> value =
std::unique_ptr<AppLaunchInfo> app_launch_info2 = std::make_unique<base::Value>(restore_data().ConvertToValue());
std::make_unique<AppLaunchInfo>( std::unique_ptr<RestoreData> restore_data =
kAppId1, kId2, apps::mojom::LaunchContainer::kLaunchContainerTab, std::make_unique<RestoreData>(std::move(value));
WindowOpenDisposition::NEW_FOREGROUND_TAB, kDisplayId2, VerifyRestoreData(*restore_data);
std::vector<base::FilePath>{base::FilePath(kFilePath2)}, }
CreateIntent(kIntentActionView, kMimeType, kShareText2));
TEST_F(RestoreDataTest, ConvertNullData) {
std::unique_ptr<AppLaunchInfo> app_launch_info3 = restore_data().AddAppLaunchInfo(nullptr);
std::make_unique<AppLaunchInfo>( EXPECT_TRUE(app_id_to_launch_list().empty());
kAppId2, kId3, apps::mojom::LaunchContainer::kLaunchContainerNone,
WindowOpenDisposition::NEW_POPUP, kDisplayId2, std::unique_ptr<base::Value> value =
std::vector<base::FilePath>{base::FilePath(kFilePath1)}, std::make_unique<base::Value>(restore_data().ConvertToValue());
CreateIntent(kIntentActionView, kMimeType, kShareText1)); std::unique_ptr<RestoreData> restore_data =
std::make_unique<RestoreData>(std::move(value));
restore_data().AddAppLaunchInfo(std::move(app_launch_info1)); EXPECT_TRUE(app_id_to_launch_list(*restore_data).empty());
restore_data().AddAppLaunchInfo(std::move(app_launch_info2));
restore_data().AddAppLaunchInfo(std::move(app_launch_info3));
EXPECT_EQ(2u, app_id_to_launch_list().size());
// Verify for |kAppId1|
const auto launch_list_it1 = app_id_to_launch_list().find(kAppId1);
EXPECT_TRUE(launch_list_it1 != app_id_to_launch_list().end());
EXPECT_EQ(2u, launch_list_it1->second.size());
const auto app_restore_data_it1 = launch_list_it1->second.find(kId1);
EXPECT_TRUE(app_restore_data_it1 != launch_list_it1->second.end());
VerifyAppRestoreData(app_restore_data_it1->second,
apps::mojom::LaunchContainer::kLaunchContainerWindow,
WindowOpenDisposition::NEW_WINDOW, kDisplayId1,
std::vector<base::FilePath>{base::FilePath(kFilePath1),
base::FilePath(kFilePath2)},
CreateIntent(kIntentActionSend, kMimeType, kShareText1));
const auto app_restore_data_it2 = launch_list_it1->second.find(kId2);
EXPECT_TRUE(app_restore_data_it2 != launch_list_it1->second.end());
VerifyAppRestoreData(app_restore_data_it2->second,
apps::mojom::LaunchContainer::kLaunchContainerTab,
WindowOpenDisposition::NEW_FOREGROUND_TAB, kDisplayId2,
std::vector<base::FilePath>{base::FilePath(kFilePath2)},
CreateIntent(kIntentActionView, kMimeType, kShareText2));
// Verify for |kAppId2|
const auto launch_list_it2 = app_id_to_launch_list().find(kAppId2);
EXPECT_TRUE(launch_list_it2 != app_id_to_launch_list().end());
EXPECT_EQ(1u, launch_list_it2->second.size());
EXPECT_EQ(kId3, launch_list_it2->second.begin()->first);
VerifyAppRestoreData(launch_list_it2->second.begin()->second,
apps::mojom::LaunchContainer::kLaunchContainerNone,
WindowOpenDisposition::NEW_POPUP, kDisplayId2,
std::vector<base::FilePath>{base::FilePath(kFilePath1)},
CreateIntent(kIntentActionView, kMimeType, kShareText1));
} }
} // namespace full_restore } // namespace full_restore
...@@ -15,6 +15,15 @@ const char kWildCardAny[] = "*"; ...@@ -15,6 +15,15 @@ const char kWildCardAny[] = "*";
const char kMimeTypeSeparator[] = "/"; const char kMimeTypeSeparator[] = "/";
constexpr size_t kMimeTypeComponentSize = 2; constexpr size_t kMimeTypeComponentSize = 2;
const char kActionKey[] = "action";
const char kUrlKey[] = "url";
const char kMimeTypeKey[] = "mime_type";
const char kFileUrlsKey[] = "file_urls";
const char kActivityNameKey[] = "activity_name";
const char kDriveShareUrlKey[] = "drive_share_url";
const char kShareTextKey[] = "share_text";
const char kShareTitleKey[] = "share_title";
// Get the intent condition value based on the condition type. // Get the intent condition value based on the condition type.
base::Optional<std::string> GetIntentConditionValueByType( base::Optional<std::string> GetIntentConditionValueByType(
apps::mojom::ConditionType condition_type, apps::mojom::ConditionType condition_type,
...@@ -345,4 +354,113 @@ bool IsIntentValid(const apps::mojom::IntentPtr& intent) { ...@@ -345,4 +354,113 @@ bool IsIntentValid(const apps::mojom::IntentPtr& intent) {
return true; return true;
} }
base::Value ConvertIntentToValue(const apps::mojom::IntentPtr& intent) {
base::Value intent_value(base::Value::Type::DICTIONARY);
if (intent->action.has_value() && !intent->action.value().empty())
intent_value.SetStringKey(kActionKey, intent->action.value());
if (intent->url.has_value()) {
DCHECK(intent->url.value().is_valid());
intent_value.SetStringKey(kUrlKey, intent->url.value().spec());
}
if (intent->mime_type.has_value() && !intent->mime_type.value().empty())
intent_value.SetStringKey(kMimeTypeKey, intent->mime_type.value());
if (intent->file_urls.has_value() && !intent->file_urls.value().empty()) {
base::Value file_urls_list(base::Value::Type::LIST);
for (auto& url : intent->file_urls.value()) {
DCHECK(url.is_valid());
file_urls_list.Append(base::Value(url.spec()));
}
intent_value.SetKey(kFileUrlsKey, std::move(file_urls_list));
}
if (intent->activity_name.has_value() &&
!intent->activity_name.value().empty()) {
intent_value.SetStringKey(kActivityNameKey, intent->activity_name.value());
}
if (intent->drive_share_url.has_value()) {
DCHECK(intent->drive_share_url.value().is_valid());
intent_value.SetStringKey(kDriveShareUrlKey,
intent->drive_share_url.value().spec());
}
if (intent->share_text.has_value() && !intent->share_text.value().empty())
intent_value.SetStringKey(kShareTextKey, intent->share_text.value());
if (intent->share_title.has_value() && !intent->share_title.value().empty())
intent_value.SetStringKey(kShareTitleKey, intent->share_title.value());
return intent_value;
}
base::Optional<std::string> GetStringValueFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
if (!dict.HasKey(key_name))
return base::nullopt;
const std::string* value = dict.FindStringKey(key_name);
if (!value || value->empty())
return base::nullopt;
return *value;
}
base::Optional<GURL> GetGurlValueFromDict(const base::DictionaryValue& dict,
const std::string& key_name) {
if (!dict.HasKey(key_name))
return base::nullopt;
const std::string* url_spec = dict.FindStringKey(key_name);
if (!url_spec)
return base::nullopt;
GURL url(*url_spec);
if (!url.is_valid())
return base::nullopt;
return url;
}
base::Optional<std::vector<::GURL>> GetFileUrlsFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
if (!dict.HasKey(key_name))
return base::nullopt;
const base::Value* value = dict.FindListKey(key_name);
if (!value || !value->is_list() || value->GetList().empty())
return base::nullopt;
std::vector<::GURL> file_urls;
for (const auto& item : value->GetList()) {
GURL url(item.GetString());
if (url.is_valid())
file_urls.push_back(std::move(url));
}
return file_urls;
}
apps::mojom::IntentPtr ConvertValueToIntent(base::Value&& value) {
auto intent = apps::mojom::Intent::New();
base::DictionaryValue* dict = nullptr;
if (!value.is_dict() || !value.GetAsDictionary(&dict) || !dict)
return intent;
intent->action = GetStringValueFromDict(*dict, kActionKey);
intent->url = GetGurlValueFromDict(*dict, kUrlKey);
intent->mime_type = GetStringValueFromDict(*dict, kMimeTypeKey);
intent->file_urls = GetFileUrlsFromDict(*dict, kFileUrlsKey);
intent->activity_name = GetStringValueFromDict(*dict, kActivityNameKey);
intent->drive_share_url = GetGurlValueFromDict(*dict, kDriveShareUrlKey);
intent->share_text = GetStringValueFromDict(*dict, kShareTextKey);
intent->share_title = GetStringValueFromDict(*dict, kShareTitleKey);
return intent;
}
} // namespace apps_util } // namespace apps_util
...@@ -78,6 +78,40 @@ bool OnlyShareToDrive(const apps::mojom::IntentPtr& intent); ...@@ -78,6 +78,40 @@ bool OnlyShareToDrive(const apps::mojom::IntentPtr& intent);
// Check the if the intent is valid, e.g. action matches content. // Check the if the intent is valid, e.g. action matches content.
bool IsIntentValid(const apps::mojom::IntentPtr& intent); bool IsIntentValid(const apps::mojom::IntentPtr& intent);
// Converts |intent| to base::Value, e.g.:
// {
// "action": "xx",
// "url": "abc.com",
// "mime_type": "text/plain",
// "file_urls": "/abc, /a",
// "activity_name": "yy",
// "drive_share_url": "aa.com",
// "share_text": "text",
// "share_title": "title",
// }
base::Value ConvertIntentToValue(const apps::mojom::IntentPtr& intent);
// Gets the string value from base::DictionaryValue, e.g. { "key": "value" }
// returns "value".
base::Optional<std::string> GetStringValueFromDict(
const base::DictionaryValue& dict,
const std::string& key_name);
// Gets GURL from base::DictionaryValue, e.g. { "url": "abc.com" } returns
// "abc.com".
base::Optional<GURL> GetGurlValueFromDict(const base::DictionaryValue& dict,
const std::string& key_name);
// Gets std::vector<::GURL> from base::DictionaryValue, e.g. { "file_urls":
// "/abc, /a" } returns std::vector<::GURL>{"/abc, /a"}.
base::Optional<std::vector<::GURL>> GetFileUrlsFromDict(
const base::DictionaryValue& dict,
const std::string& key_name);
// Converts base::Value to Intent.
apps::mojom::IntentPtr ConvertValueToIntent(base::Value&& value);
} // namespace apps_util } // namespace apps_util
#endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_ #endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
...@@ -32,6 +32,26 @@ class IntentUtilTest : public testing::Test { ...@@ -32,6 +32,26 @@ class IntentUtilTest : public testing::Test {
intent->mime_type = mime_type; intent->mime_type = mime_type;
return intent; return intent;
} }
apps::mojom::IntentPtr CreateIntent(const std::string& action,
const GURL& url,
const std::string& mime_type,
const std::vector<::GURL>& file_urls,
const std::string& activity_name,
const GURL& drive_share_url,
const std::string& share_text,
const std::string& share_title) {
auto intent = apps::mojom::Intent::New();
intent->action = action;
intent->url = url;
intent->mime_type = mime_type;
intent->file_urls = file_urls;
intent->activity_name = activity_name;
intent->drive_share_url = drive_share_url;
intent->share_text = share_text;
intent->share_title = share_title;
return intent;
}
}; };
TEST_F(IntentUtilTest, AllConditionMatches) { TEST_F(IntentUtilTest, AllConditionMatches) {
...@@ -392,3 +412,46 @@ TEST_F(IntentUtilTest, FileWithTitleText) { ...@@ -392,3 +412,46 @@ TEST_F(IntentUtilTest, FileWithTitleText) {
EXPECT_FALSE(intent->share_title.has_value()); EXPECT_FALSE(intent->share_title.has_value());
EXPECT_TRUE(apps_util::IntentMatchesFilter(intent, filter)); EXPECT_TRUE(apps_util::IntentMatchesFilter(intent, filter));
} }
TEST_F(IntentUtilTest, Convert) {
const std::string action = apps_util::kIntentActionSend;
GURL test_url1 = GURL("https://www.google.com/");
GURL test_url2 = GURL("https://www.abc.com/");
GURL test_url3 = GURL("https://www.foo.com/");
const std::string mime_type = "image/jpeg";
const std::string activity_name = "test";
const std::string share_text = "share text";
const std::string share_title = "share title";
auto src_intent =
CreateIntent(action, test_url1, mime_type, {test_url1, test_url2},
activity_name, test_url3, share_text, share_title);
base::Value value = apps_util::ConvertIntentToValue(src_intent);
auto dst_intent = apps_util::ConvertValueToIntent(std::move(value));
EXPECT_EQ(action, dst_intent->action.value());
EXPECT_EQ(test_url1, dst_intent->url.value());
EXPECT_EQ(mime_type, dst_intent->mime_type.value());
EXPECT_EQ(2u, dst_intent->file_urls->size());
EXPECT_EQ(test_url1, dst_intent->file_urls.value()[0]);
EXPECT_EQ(test_url2, dst_intent->file_urls.value()[1]);
EXPECT_EQ(activity_name, dst_intent->activity_name.value());
EXPECT_EQ(test_url3, dst_intent->drive_share_url.value());
EXPECT_EQ(share_text, dst_intent->share_text.value());
EXPECT_EQ(share_title, dst_intent->share_title.value());
}
TEST_F(IntentUtilTest, ConvertEmptyIntent) {
auto intent = apps::mojom::Intent::New();
base::Value value = apps_util::ConvertIntentToValue(intent);
auto dst_intent = apps_util::ConvertValueToIntent(std::move(value));
EXPECT_FALSE(dst_intent->action.has_value());
EXPECT_FALSE(dst_intent->url.has_value());
EXPECT_FALSE(dst_intent->mime_type.has_value());
EXPECT_FALSE(dst_intent->file_urls.has_value());
EXPECT_FALSE(dst_intent->activity_name.has_value());
EXPECT_FALSE(dst_intent->drive_share_url.has_value());
EXPECT_FALSE(dst_intent->share_text.has_value());
EXPECT_FALSE(dst_intent->share_title.has_value());
}
...@@ -323,7 +323,9 @@ struct IntentFilter { ...@@ -323,7 +323,9 @@ struct IntentFilter {
}; };
// Action and resource handling request. This includes the scheme and URL at // Action and resource handling request. This includes the scheme and URL at
// the moment, and will be extended to handle files in the future. // the moment, and will be extended to handle files in the future. This should
// be kept in sync with ConvertIntentToValue and ConvertValueToIntent in
// components/services/app_service/public/cpp/intent_util.*
struct Intent { struct Intent {
string? action; // Intent action. e.g. view, send. string? action; // Intent action. e.g. view, send.
url.mojom.Url? url; // The URL of the intent. e.g. https://www.google.com/. url.mojom.Url? url; // The URL of the intent. e.g. https://www.google.com/.
......
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