Commit e64ee29a authored by Toni Barzic's avatar Toni Barzic Committed by Commit Bot

Initial commit for temporary holding space

Adds a feature flag and general code structure that will be used for the
feature:
*   chrome/browser/ui/ash/holding_space - browser context keyed service
    that keeps track of per-user holding space items, and that will be
    used as an entry point to add items to the holding space from
    Chrome.
*   ash/public/cpp/holding_space - general holding space data model,
    that contains information about items that have been added to the
    holding space, and that propagates model changes between chrome
    and ash
*   ash/holding_space - the UI implementation for the holding space.

The logic is pretty bare, mostly focused on propagating model state
updates to ash. The UI implementation, and entry points to add items
will be done in coming weeks.

BUG=1106991

Change-Id: Id0a70929aecfe4164b613a39db42b9412368abbd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2310902Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarAlex Newcomer <newcomer@chromium.org>
Commit-Queue: Toni Baržić <tbarzic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#791013}
parent 8d7fd942
......@@ -408,6 +408,8 @@ component("ash") {
"highlighter/highlighter_result_view.h",
"highlighter/highlighter_view.cc",
"highlighter/highlighter_view.h",
"holding_space/holding_space_presenter.cc",
"holding_space/holding_space_presenter.h",
"home_screen/drag_window_from_shelf_controller.cc",
"home_screen/drag_window_from_shelf_controller.h",
"home_screen/home_launcher_gesture_handler.cc",
......@@ -1810,6 +1812,7 @@ test("ash_unittests") {
"frame/non_client_frame_view_ash_unittest.cc",
"highlighter/highlighter_controller_unittest.cc",
"highlighter/highlighter_gesture_util_unittest.cc",
"holding_space/holding_space_presenter_unittest.cc",
"home_screen/drag_window_from_shelf_controller_test_api.cc",
"home_screen/drag_window_from_shelf_controller_test_api.h",
"home_screen/drag_window_from_shelf_controller_unittest.cc",
......
tbarzic@chromium.org
newcomer@chromium.org
# COMPONENT: UI>Shell>HoldingSpace
// 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/holding_space/holding_space_presenter.h"
#include "ash/public/cpp/holding_space/holding_space_item.h"
#include "base/stl_util.h"
namespace ash {
HoldingSpacePresenter::HoldingSpacePresenter() {
HoldingSpaceController* const controller = HoldingSpaceController::Get();
controller_observer_.Add(controller);
if (controller->model())
HandleNewModel(controller->model());
}
HoldingSpacePresenter::~HoldingSpacePresenter() = default;
void HoldingSpacePresenter::OnHoldingSpaceModelAttached(
HoldingSpaceModel* model) {
HandleNewModel(model);
}
void HoldingSpacePresenter::OnHoldingSpaceModelDetached(
HoldingSpaceModel* model) {
model_observer_.Remove(model);
item_ids_.clear();
}
void HoldingSpacePresenter::OnHoldingSpaceItemAdded(
const HoldingSpaceItem* item) {
item_ids_.push_back(item->id());
}
void HoldingSpacePresenter::OnHoldingSpaceItemRemoved(
const HoldingSpaceItem* item) {
base::Erase(item_ids_, item->id());
}
void HoldingSpacePresenter::HandleNewModel(HoldingSpaceModel* model) {
model_observer_.Add(model);
for (auto& item : model->items())
item_ids_.push_back(item->id());
}
} // namespace ash
// 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 ASH_HOLDING_SPACE_HOLDING_SPACE_PRESENTER_H_
#define ASH_HOLDING_SPACE_HOLDING_SPACE_PRESENTER_H_
#include <string>
#include <vector>
#include "ash/ash_export.h"
#include "ash/public/cpp/holding_space/holding_space_controller.h"
#include "ash/public/cpp/holding_space/holding_space_controller_observer.h"
#include "ash/public/cpp/holding_space/holding_space_model.h"
#include "ash/public/cpp/holding_space/holding_space_model_observer.h"
#include "base/scoped_observer.h"
namespace ash {
class HoldingSpaceItem;
// Manages the temporary holding space UI for a root window.
// The main job of the class is
// * to observe the holding space model and update item representations in the
// holding space UI.
// * to handle user actions within the holding space UI, and updates the
// holding space model accordingly.
// NOTE: Currently this class only tracks the list of items within the active
// holding space model.
class ASH_EXPORT HoldingSpacePresenter : public HoldingSpaceControllerObserver,
public HoldingSpaceModelObserver {
public:
HoldingSpacePresenter();
HoldingSpacePresenter(const HoldingSpacePresenter& other) = delete;
HoldingSpacePresenter& operator=(const HoldingSpacePresenter& other) = delete;
~HoldingSpacePresenter() override;
// HoldingSpaceControllerObserver:
void OnHoldingSpaceModelAttached(HoldingSpaceModel* model) override;
void OnHoldingSpaceModelDetached(HoldingSpaceModel* model) override;
// HoldingSpaceModelObserver:
void OnHoldingSpaceItemAdded(const HoldingSpaceItem* item) override;
void OnHoldingSpaceItemRemoved(const HoldingSpaceItem* item) override;
const std::vector<std::string>& item_ids() const { return item_ids_; }
private:
// Handles the items from the model, and starts observing the model.
void HandleNewModel(HoldingSpaceModel* model);
// IDs of items in the active holding space model, as observed by the holding
// space presenter.
std::vector<std::string> item_ids_;
ScopedObserver<HoldingSpaceController, HoldingSpaceControllerObserver>
controller_observer_{this};
ScopedObserver<HoldingSpaceModel, HoldingSpaceModelObserver> model_observer_{
this};
};
} // namespace ash
#endif // ASH_HOLDING_SPACE_HOLDING_SPACE_PRESENTER_H_
// 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/holding_space/holding_space_presenter.h"
#include <memory>
#include <utility>
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/holding_space/holding_space_controller.h"
#include "ash/public/cpp/holding_space/holding_space_item.h"
#include "ash/public/cpp/holding_space/holding_space_model.h"
#include "ash/test/ash_test_base.h"
#include "base/test/scoped_feature_list.h"
namespace ash {
class HoldingSpacePresenterTest : public AshTestBase {
public:
HoldingSpacePresenterTest() {
scoped_feature_list_.InitAndEnableFeature(features::kTemporaryHoldingSpace);
}
HoldingSpacePresenterTest(const HoldingSpacePresenterTest& other) = delete;
HoldingSpacePresenterTest& operator=(const HoldingSpacePresenterTest& other) =
delete;
~HoldingSpacePresenterTest() override = default;
// AshTestBase:
void SetUp() override {
AshTestBase::SetUp();
holding_space_presenter_ = std::make_unique<HoldingSpacePresenter>();
}
void TearDown() override {
holding_space_presenter_.reset();
AshTestBase::TearDown();
}
HoldingSpaceModel* primary_model() { return &primary_model_; }
HoldingSpacePresenter* GetHoldingSpacePresenter() {
return holding_space_presenter_.get();
}
private:
std::unique_ptr<HoldingSpacePresenter> holding_space_presenter_;
HoldingSpaceModel primary_model_;
base::test::ScopedFeatureList scoped_feature_list_;
};
// Tests that items already in the model when an active model is set get added
// to the holding space.
TEST_F(HoldingSpacePresenterTest, ModelWithExistingItems) {
EXPECT_EQ(std::vector<std::string>(), GetHoldingSpacePresenter()->item_ids());
const std::string item_1_id = "item_1";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_1_id));
ASSERT_TRUE(primary_model()->GetItem(item_1_id));
ASSERT_EQ(item_1_id, primary_model()->GetItem(item_1_id)->id());
const std::string item_2_id = "item_2";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_2_id));
ASSERT_TRUE(primary_model()->GetItem(item_2_id));
ASSERT_EQ(item_2_id, primary_model()->GetItem(item_2_id)->id());
// Note - the item ID is missing a suffix to verify the items do not get
// sorted by their IDs.
const std::string item_3_id = "item";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_3_id));
HoldingSpaceController::Get()->SetModel(primary_model());
EXPECT_EQ(std::vector<std::string>({item_1_id, item_2_id, item_3_id}),
GetHoldingSpacePresenter()->item_ids());
HoldingSpaceController::Get()->SetModel(nullptr);
EXPECT_EQ(std::vector<std::string>(), GetHoldingSpacePresenter()->item_ids());
}
// Tests that the holding space presenter picks up existing model items if a
// model is set and non-empty on presenter's creation.
TEST_F(HoldingSpacePresenterTest, NonEmptyModelOnPresenterCreation) {
// Initiate non-empty holding space model.
const std::string item_1_id = "item_1";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_1_id));
const std::string item_2_id = "item_2";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_2_id));
HoldingSpaceController::Get()->SetModel(primary_model());
// Create a new holding space presenter, and verify it picked up the existing
// model items.
auto secondary_presenter = std::make_unique<HoldingSpacePresenter>();
EXPECT_EQ(std::vector<std::string>({item_1_id, item_2_id}),
secondary_presenter->item_ids());
HoldingSpaceController::Get()->SetModel(nullptr);
EXPECT_EQ(std::vector<std::string>(), GetHoldingSpacePresenter()->item_ids());
EXPECT_EQ(std::vector<std::string>(), secondary_presenter->item_ids());
}
// Verifies that holding space handles holding space model changes.
TEST_F(HoldingSpacePresenterTest, AddingAndRemovingModelItems) {
HoldingSpaceController::Get()->SetModel(primary_model());
EXPECT_EQ(std::vector<std::string>(), GetHoldingSpacePresenter()->item_ids());
// Add some items to the model, and verify the items get picked up by the
// presenter.
const std::string item_1_id = "item_1";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_1_id));
EXPECT_EQ(std::vector<std::string>({item_1_id}),
GetHoldingSpacePresenter()->item_ids());
const std::string item_2_id = "item_2";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_2_id));
EXPECT_EQ(std::vector<std::string>({item_1_id, item_2_id}),
GetHoldingSpacePresenter()->item_ids());
const std::string item_3_id = "item_3";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_3_id));
EXPECT_EQ(std::vector<std::string>({item_1_id, item_2_id, item_3_id}),
GetHoldingSpacePresenter()->item_ids());
primary_model()->RemoveItem(item_2_id);
EXPECT_EQ(std::vector<std::string>({item_1_id, item_3_id}),
GetHoldingSpacePresenter()->item_ids());
primary_model()->RemoveAll();
EXPECT_EQ(std::vector<std::string>(), GetHoldingSpacePresenter()->item_ids());
const std::string item_4_id = "item_4";
primary_model()->AddItem(std::make_unique<HoldingSpaceItem>(item_4_id));
EXPECT_EQ(std::vector<std::string>({item_4_id}),
GetHoldingSpacePresenter()->item_ids());
// Holding space should be cleared if the active model is reset.
HoldingSpaceController::Get()->SetModel(nullptr);
EXPECT_EQ(std::vector<std::string>(), GetHoldingSpacePresenter()->item_ids());
}
// Verifies that the holding space gets updated when the active model changes.
TEST_F(HoldingSpacePresenterTest, ModelChange) {
const std::string primary_model_item_id = "primary_model_item";
primary_model()->AddItem(
std::make_unique<HoldingSpaceItem>(primary_model_item_id));
HoldingSpaceController::Get()->SetModel(primary_model());
EXPECT_EQ(std::vector<std::string>({primary_model_item_id}),
GetHoldingSpacePresenter()->item_ids());
HoldingSpaceModel secondary_model;
const std::string secondary_model_item_id = "secondary_model_item";
secondary_model.AddItem(
std::make_unique<HoldingSpaceItem>(secondary_model_item_id));
EXPECT_EQ(std::vector<std::string>({primary_model_item_id}),
GetHoldingSpacePresenter()->item_ids());
HoldingSpaceController::Get()->SetModel(&secondary_model);
EXPECT_EQ(std::vector<std::string>({secondary_model_item_id}),
GetHoldingSpacePresenter()->item_ids());
HoldingSpaceController::Get()->SetModel(nullptr);
EXPECT_EQ(std::vector<std::string>(), GetHoldingSpacePresenter()->item_ids());
}
} // namespace ash
......@@ -122,6 +122,14 @@ component("cpp") {
"frame_utils.cc",
"frame_utils.h",
"gesture_action_type.h",
"holding_space/holding_space_controller.cc",
"holding_space/holding_space_controller.h",
"holding_space/holding_space_controller_observer.h",
"holding_space/holding_space_item.cc",
"holding_space/holding_space_item.h",
"holding_space/holding_space_model.cc",
"holding_space/holding_space_model.h",
"holding_space/holding_space_model_observer.h",
"image_downloader.cc",
"image_downloader.h",
"ime_controller.cc",
......
......@@ -131,6 +131,9 @@ const base::Feature kMaintainShelfStateWhenEnteringOverview{
"MaintainShelfStateWhenEnteringOverview",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kTemporaryHoldingSpace{"TemporaryHoldingSpace",
base::FEATURE_DISABLED_BY_DEFAULT};
bool IsAllowAmbientEQEnabled() {
return base::FeatureList::IsEnabled(kAllowAmbientEQ);
}
......@@ -277,6 +280,10 @@ bool IsMaintainShelfStateWhenEnteringOverviewEnabled() {
return base::FeatureList::IsEnabled(kMaintainShelfStateWhenEnteringOverview);
}
bool IsTemporaryHoldingSpaceEnabled() {
return base::FeatureList::IsEnabled(kTemporaryHoldingSpace);
}
namespace {
// The boolean flag indicating if "WebUITabStrip" feature is enabled in Chrome.
......
......@@ -167,6 +167,11 @@ ASH_PUBLIC_EXPORT extern const base::Feature kNotificationsInContextMenu;
ASH_PUBLIC_EXPORT extern const base::Feature
kMaintainShelfStateWhenEnteringOverview;
// Enables the experimental productivity feature that aims to reduce context
// switching by enabling users to collect content and transfer or access it
// later.
ASH_PUBLIC_EXPORT extern const base::Feature kTemporaryHoldingSpace;
ASH_PUBLIC_EXPORT bool IsAllowAmbientEQEnabled();
ASH_PUBLIC_EXPORT bool IsAltTabLimitedToActiveDesk();
......@@ -231,6 +236,8 @@ ASH_PUBLIC_EXPORT bool IsNotificationsInContextMenuEnabled();
ASH_PUBLIC_EXPORT bool IsMaintainShelfStateWhenEnteringOverviewEnabled();
ASH_PUBLIC_EXPORT bool IsTemporaryHoldingSpaceEnabled();
// These two functions are supposed to be temporary functions to set or get
// whether "WebUITabStrip" feature is enabled from Chrome.
ASH_PUBLIC_EXPORT void SetWebUITabStripEnabled(bool enabled);
......
file://ash/holding_space/OWNERS
# COMPONENT: UI>Shell>HoldingSpace
// 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_controller.h"
#include "ash/public/cpp/holding_space/holding_space_controller_observer.h"
#include "base/check.h"
namespace ash {
namespace {
HoldingSpaceController* g_instance = nullptr;
} // namespace
HoldingSpaceController::HoldingSpaceController() {
CHECK(!g_instance);
g_instance = this;
}
HoldingSpaceController::~HoldingSpaceController() {
CHECK_EQ(g_instance, this);
SetModel(nullptr);
g_instance = nullptr;
}
// static
HoldingSpaceController* HoldingSpaceController::Get() {
return g_instance;
}
void HoldingSpaceController::AddObserver(
HoldingSpaceControllerObserver* observer) {
observers_.AddObserver(observer);
}
void HoldingSpaceController::RemoveObserver(
HoldingSpaceControllerObserver* observer) {
observers_.RemoveObserver(observer);
}
void HoldingSpaceController::SetModel(HoldingSpaceModel* model) {
if (model_) {
for (auto& observer : observers_)
observer.OnHoldingSpaceModelDetached(model_);
}
model_ = model;
if (model_) {
for (auto& observer : observers_)
observer.OnHoldingSpaceModelAttached(model_);
}
}
} // namespace ash
// 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 ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_CONTROLLER_H_
#define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_CONTROLLER_H_
#include "ash/public/cpp/ash_public_export.h"
#include "base/observer_list.h"
namespace ash {
class HoldingSpaceControllerObserver;
class HoldingSpaceModel;
// Keeps track of the currentily active holding space model.
// There is expected to exist at most one instance of this class at a time. In
// production the instance is owned by ash::Shell. The instance can be retrieved
// using HoldingSpaceController::Get().
class ASH_PUBLIC_EXPORT HoldingSpaceController {
public:
HoldingSpaceController();
HoldingSpaceController(const HoldingSpaceController& other) = delete;
HoldingSpaceController& operator=(const HoldingSpaceController& other) =
delete;
~HoldingSpaceController();
// Returns the global HoldingSpaceController instance. It's set in the
// HoldingSpaceController constructor, and reset in the destructor. The
// instance is owned by ash shell.
static HoldingSpaceController* Get();
void AddObserver(HoldingSpaceControllerObserver* observer);
void RemoveObserver(HoldingSpaceControllerObserver* observer);
// Sets the active model - the caller is expected to maintain the ownership.
void SetModel(HoldingSpaceModel* model);
HoldingSpaceModel* model() { return model_; }
private:
// The currently active holding space model, set by SetModel(). The client
// that sets the model is expected to maintain the model ownership.
HoldingSpaceModel* model_ = nullptr;
base::ObserverList<HoldingSpaceControllerObserver> observers_;
};
} // namespace ash
#endif // ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_CONTROLLER_H_
// 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 ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_CONTROLLER_OBSERVER_H_
#define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_CONTROLLER_OBSERVER_H_
#include "ash/public/cpp/ash_public_export.h"
#include "base/observer_list_types.h"
namespace ash {
class HoldingSpaceModel;
class ASH_PUBLIC_EXPORT HoldingSpaceControllerObserver
: public base::CheckedObserver {
public:
// Called when a model gets attached to the HoldingSpaceController.
virtual void OnHoldingSpaceModelAttached(HoldingSpaceModel* model) = 0;
// Called when a model gets detached from the HoldingSpaceController.
virtual void OnHoldingSpaceModelDetached(HoldingSpaceModel* model) = 0;
};
} // namespace ash
#endif // ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_CONTROLLER_OBSERVER_H_
// 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"
namespace ash {
HoldingSpaceItem::HoldingSpaceItem(const std::string& id) : id_(id) {}
HoldingSpaceItem::~HoldingSpaceItem() = default;
} // namespace ash
// 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 ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_ITEM_H_
#define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_ITEM_H_
#include <string>
#include "ash/public/cpp/ash_public_export.h"
#include "base/optional.h"
#include "base/strings/string16.h"
namespace ash {
// Contains data needed to display a single item in the temporary holding space
// UI.
class ASH_PUBLIC_EXPORT HoldingSpaceItem {
public:
explicit HoldingSpaceItem(const std::string& id);
HoldingSpaceItem(const HoldingSpaceItem& other) = delete;
HoldingSpaceItem operator=(const HoldingSpaceItem& other) = delete;
~HoldingSpaceItem();
const std::string& id() const { return id_; }
void set_text(const base::string16& text) { text_ = text; }
const base::Optional<base::string16>& text() const { return text_; }
private:
// The holding space item ID assigned to the item.
std::string id_;
// If set, the text data associated with the item.
base::Optional<base::string16> text_;
};
} // namespace ash
#endif // ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_ITEM_H_
// 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_model.h"
#include <algorithm>
#include "ash/public/cpp/holding_space/holding_space_item.h"
#include "ash/public/cpp/holding_space/holding_space_model_observer.h"
#include "base/check.h"
namespace ash {
HoldingSpaceModel::HoldingSpaceModel() = default;
HoldingSpaceModel::~HoldingSpaceModel() = default;
void HoldingSpaceModel::AddItem(std::unique_ptr<HoldingSpaceItem> item) {
DCHECK(!GetItem(item->id()));
const HoldingSpaceItem* item_ptr = item.get();
items_.push_back(std::move(item));
for (auto& observer : observers_)
observer.OnHoldingSpaceItemAdded(item_ptr);
}
void HoldingSpaceModel::RemoveItem(const std::string& id) {
auto item_it = std::find_if(
items_.begin(), items_.end(),
[&id](const std::unique_ptr<HoldingSpaceItem>& item) -> bool {
return item->id() == id;
});
DCHECK(item_it != items_.end());
// Keep the item around at least until the observers have been notified of the
// item removal.
std::unique_ptr<HoldingSpaceItem> item = std::move(*item_it);
items_.erase(item_it);
for (auto& observer : observers_)
observer.OnHoldingSpaceItemRemoved(item.get());
}
void HoldingSpaceModel::RemoveAll() {
// Clear the item list, but keep the items around until the observers have
// been notified of the item removal.
ItemList items;
items.swap(items_);
for (auto& item : items) {
for (auto& observer : observers_)
observer.OnHoldingSpaceItemRemoved(item.get());
}
}
const HoldingSpaceItem* HoldingSpaceModel::GetItem(
const std::string& id) const {
auto item_it = std::find_if(
items_.begin(), items_.end(),
[&id](const std::unique_ptr<HoldingSpaceItem>& item) -> bool {
return item->id() == id;
});
if (item_it == items_.end())
return nullptr;
return item_it->get();
}
void HoldingSpaceModel::AddObserver(HoldingSpaceModelObserver* observer) {
observers_.AddObserver(observer);
}
void HoldingSpaceModel::RemoveObserver(HoldingSpaceModelObserver* observer) {
observers_.RemoveObserver(observer);
}
} // namespace ash
// 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 ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_H_
#define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_H_
#include <memory>
#include <string>
#include <vector>
#include "ash/public/cpp/ash_public_export.h"
#include "base/observer_list.h"
namespace ash {
class HoldingSpaceItem;
class HoldingSpaceModelObserver;
// The data model for the temporary holding space UI. It contains the list of
// items that should be shown in the temporary holding space UI - each item will
// represent a piece of data added to the holding space by the user (for
// example, text, URLs, or images).
// The main goal of the class is to provide UI implementation agnostic
// information about items added to the holding space, and to provide an
// interface to propagate holding space changes between ash and Chrome.
class ASH_PUBLIC_EXPORT HoldingSpaceModel {
public:
using ItemList = std::vector<std::unique_ptr<HoldingSpaceItem>>;
HoldingSpaceModel();
HoldingSpaceModel(const HoldingSpaceModel& other) = delete;
HoldingSpaceModel& operator=(const HoldingSpaceModel& other) = delete;
~HoldingSpaceModel();
// Adds a single holding space item to the model.
void AddItem(std::unique_ptr<HoldingSpaceItem> item);
// Removes a single holding space item from the model.
void RemoveItem(const std::string& id);
// Removes all the items from the model.
void RemoveAll();
// Gets a single holding space item.
// Returns nullptr if the item does not exist in the model.
const HoldingSpaceItem* GetItem(const std::string& id) const;
const ItemList& items() const { return items_; }
void AddObserver(HoldingSpaceModelObserver* observer);
void RemoveObserver(HoldingSpaceModelObserver* observer);
private:
// The list of items added to the model in the order they have been added to
// the model.
ItemList items_;
base::ObserverList<HoldingSpaceModelObserver> observers_;
};
} // namespace ash
#endif // ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_H_
// 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 ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_OBSERVER_H_
#define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_OBSERVER_H_
#include "ash/public/cpp/ash_public_export.h"
#include "base/observer_list_types.h"
namespace ash {
class HoldingSpaceItem;
class ASH_PUBLIC_EXPORT HoldingSpaceModelObserver
: public base::CheckedObserver {
public:
// Called when an item gets added to the holding space model.
virtual void OnHoldingSpaceItemAdded(const HoldingSpaceItem* item) = 0;
// Called when an item gets removed from the holding space model.
virtual void OnHoldingSpaceItemRemoved(const HoldingSpaceItem* item) = 0;
};
} // namespace ash
#endif // ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_OBSERVER_H_
......@@ -77,6 +77,7 @@
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/ash_prefs.h"
#include "ash/public/cpp/ash_switches.h"
#include "ash/public/cpp/holding_space/holding_space_controller.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/public/cpp/shelf_model.h"
#include "ash/public/cpp/shell_window_ids.h"
......@@ -1207,6 +1208,9 @@ void Shell::Init(
std::make_unique<DisplayAlignmentController>();
}
if (features::IsTemporaryHoldingSpaceEnabled())
holding_space_controller_ = std::make_unique<HoldingSpaceController>();
for (auto& observer : shell_observers_)
observer.OnShellInitialized();
......
......@@ -117,6 +117,7 @@ class FocusCycler;
class FrameThrottlingController;
class HighContrastController;
class HighlighterController;
class HoldingSpaceController;
class HomeScreenController;
class ImeControllerImpl;
class ImmersiveContext;
......@@ -670,6 +671,7 @@ class ASH_EXPORT Shell : public SessionObserver,
std::unique_ptr<DisplaySpeakerController> display_speaker_controller_;
std::unique_ptr<DragDropController> drag_drop_controller_;
std::unique_ptr<FocusCycler> focus_cycler_;
std::unique_ptr<HoldingSpaceController> holding_space_controller_;
std::unique_ptr<HomeScreenController> home_screen_controller_;
std::unique_ptr<ImeControllerImpl> ime_controller_;
std::unique_ptr<ImmersiveContext> immersive_context_;
......
......@@ -33,6 +33,7 @@
#include "chrome/browser/chromeos/smb_client/smb_service_factory.h"
#include "chrome/browser/chromeos/tether/tether_service_factory.h"
#include "chrome/browser/chromeos/web_applications/crosh_loader_factory.h"
#include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h"
#if defined(USE_CUPS)
#include "chrome/browser/chromeos/extensions/printing/printing_api_handler.h"
......@@ -65,6 +66,7 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
file_manager::VolumeManagerFactory::GetInstance();
file_system_provider::ServiceFactory::GetInstance();
guest_os::GuestOsRegistryServiceFactory::GetInstance();
ash::HoldingSpaceKeyedServiceFactory::GetInstance();
KerberosCredentialsManagerFactory::GetInstance();
launcher_search_provider::ServiceFactory::GetInstance();
OwnerSettingsServiceChromeOSFactory::GetInstance();
......
......@@ -1814,6 +1814,10 @@ static_library("ui") {
"ash/chrome_shell_delegate.h",
"ash/clipboard_util.cc",
"ash/clipboard_util.h",
"ash/holding_space/holding_space_keyed_service.cc",
"ash/holding_space/holding_space_keyed_service.h",
"ash/holding_space/holding_space_keyed_service_factory.cc",
"ash/holding_space/holding_space_keyed_service_factory.h",
"ash/image_downloader_impl.cc",
"ash/image_downloader_impl.h",
"ash/ime_controller_client.cc",
......
file://ash/holding_space/OWNERS
# COMPONENT: UI>Shell>HoldingSpace
// 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/ui/ash/holding_space/holding_space_keyed_service.h"
#include "ash/public/cpp/holding_space/holding_space_controller.h"
#include "ash/public/cpp/holding_space/holding_space_item.h"
#include "base/guid.h"
namespace ash {
HoldingSpaceKeyedService::HoldingSpaceKeyedService(
content::BrowserContext* context) {}
HoldingSpaceKeyedService::~HoldingSpaceKeyedService() = default;
void HoldingSpaceKeyedService::AddTextItem(const base::string16& text) {
auto item = std::make_unique<HoldingSpaceItem>(base::GenerateGUID());
item->set_text(text);
holding_space_model_.AddItem(std::move(item));
}
void HoldingSpaceKeyedService::ActivateModel() {
HoldingSpaceController::Get()->SetModel(&holding_space_model_);
}
} // namespace ash
// 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_UI_ASH_HOLDING_SPACE_HOLDING_SPACE_KEYED_SERVICE_H_
#define CHROME_BROWSER_UI_ASH_HOLDING_SPACE_HOLDING_SPACE_KEYED_SERVICE_H_
#include "ash/public/cpp/holding_space/holding_space_model.h"
#include "base/strings/string16.h"
#include "components/keyed_service/core/keyed_service.h"
namespace content {
class BrowserContext;
}
namespace ash {
// Browser context keyed service that:
// * Manages the temporary holding space per-profile data model.
// * Serves as an entry point to add holding space items from Chrome.
class HoldingSpaceKeyedService : public KeyedService {
public:
explicit HoldingSpaceKeyedService(content::BrowserContext* context);
HoldingSpaceKeyedService(const HoldingSpaceKeyedService& other) = delete;
HoldingSpaceKeyedService& operator=(const HoldingSpaceKeyedService& other) =
delete;
~HoldingSpaceKeyedService() override;
// Sets the holding space model managed by this service as the active
// model.
void ActivateModel();
// Adds a text item to the service's holding space model.
// |text|: The item's text value.
void AddTextItem(const base::string16& text);
const HoldingSpaceModel* model_for_testing() const {
return &holding_space_model_;
}
private:
HoldingSpaceModel holding_space_model_;
};
} // namespace ash
#endif // CHROME_BROWSER_UI_ASH_HOLDING_SPACE_HOLDING_SPACE_KEYED_SERVICE_H_
// 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/ui/ash/holding_space/holding_space_keyed_service_factory.h"
#include "ash/public/cpp/ash_features.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
namespace ash {
// static
HoldingSpaceKeyedServiceFactory*
HoldingSpaceKeyedServiceFactory::GetInstance() {
static base::NoDestructor<HoldingSpaceKeyedServiceFactory> factory;
return factory.get();
}
HoldingSpaceKeyedServiceFactory::HoldingSpaceKeyedServiceFactory()
: BrowserContextKeyedServiceFactory(
"HoldingSpaceService",
BrowserContextDependencyManager::GetInstance()) {}
HoldingSpaceKeyedService* HoldingSpaceKeyedServiceFactory::GetService(
content::BrowserContext* context) {
return static_cast<HoldingSpaceKeyedService*>(
GetInstance()->GetServiceForBrowserContext(context, /*create=*/true));
}
KeyedService* HoldingSpaceKeyedServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
if (!features::IsTemporaryHoldingSpaceEnabled())
return nullptr;
// TODO(https://crbug.com/1107713): Support multi-profile.
if (!chromeos::ProfileHelper::IsPrimaryProfile(
Profile::FromBrowserContext(context))) {
return nullptr;
}
auto* service = new HoldingSpaceKeyedService(context);
service->ActivateModel();
return service;
}
bool HoldingSpaceKeyedServiceFactory::ServiceIsCreatedWithBrowserContext()
const {
return true;
}
} // namespace ash
// 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_UI_ASH_HOLDING_SPACE_HOLDING_SPACE_KEYED_SERVICE_FACTORY_H_
#define CHROME_BROWSER_UI_ASH_HOLDING_SPACE_HOLDING_SPACE_KEYED_SERVICE_FACTORY_H_
#include "base/no_destructor.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
namespace content {
class BrowserContext;
}
namespace ash {
class HoldingSpaceKeyedService;
// Factory class for browser context keyed HoldingSpace services.
class HoldingSpaceKeyedServiceFactory
: public BrowserContextKeyedServiceFactory {
public:
static HoldingSpaceKeyedServiceFactory* GetInstance();
HoldingSpaceKeyedService* GetService(content::BrowserContext* context);
protected:
// BrowserContextKeyedServiceFactory:
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
bool ServiceIsCreatedWithBrowserContext() const override;
private:
friend base::NoDestructor<HoldingSpaceKeyedServiceFactory>;
HoldingSpaceKeyedServiceFactory();
HoldingSpaceKeyedServiceFactory(
const HoldingSpaceKeyedServiceFactory& other) = delete;
HoldingSpaceKeyedServiceFactory& operator=(
const HoldingSpaceKeyedServiceFactory& other) = delete;
};
} // namespace ash
#endif // CHROME_BROWSER_UI_ASH_HOLDING_SPACE_HOLDING_SPACE_KEYED_SERVICE_FACTORY_H_
// 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/ui/ash/holding_space/holding_space_keyed_service.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/holding_space/holding_space_controller.h"
#include "ash/public/cpp/holding_space/holding_space_item.h"
#include "ash/public/cpp/holding_space/holding_space_model.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/account_id/account_id.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/user_manager/scoped_user_manager.h"
namespace ash {
class HoldingSpaceKeyedServiceTest : public BrowserWithTestWindowTest {
public:
HoldingSpaceKeyedServiceTest()
: fake_user_manager_(new chromeos::FakeChromeUserManager),
user_manager_enabler_(base::WrapUnique(fake_user_manager_)) {
scoped_feature_list_.InitAndEnableFeature(features::kTemporaryHoldingSpace);
}
HoldingSpaceKeyedServiceTest(const HoldingSpaceKeyedServiceTest& other) =
delete;
HoldingSpaceKeyedServiceTest& operator=(
const HoldingSpaceKeyedServiceTest& other) = delete;
~HoldingSpaceKeyedServiceTest() override = default;
TestingProfile* CreateProfile() override {
const std::string kPrimaryProfileName = "primary_profile";
const AccountId account_id(AccountId::FromUserEmail(kPrimaryProfileName));
fake_user_manager_->AddUser(account_id);
fake_user_manager_->LoginUser(account_id);
return profile_manager()->CreateTestingProfile(kPrimaryProfileName);
}
TestingProfile* CreateSecondaryProfile() {
const std::string kSecondaryProfileName = "secondary_profile";
const AccountId account_id(AccountId::FromUserEmail(kSecondaryProfileName));
fake_user_manager_->AddUser(account_id);
fake_user_manager_->LoginUser(account_id);
return profile_manager()->CreateTestingProfile(
kSecondaryProfileName,
std::unique_ptr<sync_preferences::PrefServiceSyncable>(),
base::ASCIIToUTF16("Test profile"), 1 /*avatar_id*/,
std::string() /*supervised_user_id*/,
TestingProfile::TestingFactories());
}
private:
chromeos::FakeChromeUserManager* fake_user_manager_;
user_manager::ScopedUserManager user_manager_enabler_;
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(HoldingSpaceKeyedServiceTest, AddTextItem) {
// Verify that the holding space model gets set even if the holding space
// keyed service is not explicitly created.
HoldingSpaceModel* const initial_model =
HoldingSpaceController::Get()->model();
EXPECT_TRUE(initial_model);
HoldingSpaceKeyedService* const holding_space_service =
HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(GetProfile());
const base::string16 item_1 = base::ASCIIToUTF16("Test text item");
holding_space_service->AddTextItem(item_1);
const base::string16 item_2 = base::ASCIIToUTF16("Second test text item");
holding_space_service->AddTextItem(item_2);
EXPECT_EQ(initial_model, HoldingSpaceController::Get()->model());
EXPECT_EQ(HoldingSpaceController::Get()->model(),
holding_space_service->model_for_testing());
std::vector<base::string16> text_items;
for (auto& item : HoldingSpaceController::Get()->model()->items()) {
text_items.push_back(item->text().value_or(base::ASCIIToUTF16("null")));
}
EXPECT_EQ(std::vector<base::string16>({item_1, item_2}), text_items);
}
TEST_F(HoldingSpaceKeyedServiceTest, SecondaryUserProfile) {
HoldingSpaceKeyedService* const primary_holding_space_service =
HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(GetProfile());
TestingProfile* const second_profile = CreateSecondaryProfile();
EXPECT_FALSE(HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(
second_profile));
// Just creating a secondary profile should not change the active model.
EXPECT_EQ(HoldingSpaceController::Get()->model(),
primary_holding_space_service->model_for_testing());
}
} // namespace ash
......@@ -4594,6 +4594,7 @@ test("unit_tests") {
"../browser/ui/ash/assistant/conversation_starters_parser_unittest.cc",
"../browser/ui/ash/assistant/device_actions_unittest.cc",
"../browser/ui/ash/assistant/search_and_assistant_enabled_checker_unittest.cc",
"../browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc",
"../browser/ui/ash/ime_controller_client_unittest.cc",
"../browser/ui/ash/keyboard/chrome_keyboard_ui_unittest.cc",
"../browser/ui/ash/keyboard/chrome_keyboard_web_contents_unittest.cc",
......
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