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 "chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.h"
6 
7 #include <string>
8 
9 #include "ash/public/cpp/ash_features.h"
10 #include "ash/public/cpp/holding_space/holding_space_controller.h"
11 #include "ash/public/cpp/holding_space/holding_space_image.h"
12 #include "ash/public/cpp/holding_space/holding_space_item.h"
13 #include "ash/public/cpp/holding_space/holding_space_model.h"
14 #include "ash/public/cpp/holding_space/holding_space_test_api.h"
15 #include "base/callback_helpers.h"
16 #include "base/files/file_util.h"
17 #include "base/scoped_observer.h"
18 #include "base/unguessable_token.h"
19 #include "chrome/browser/chromeos/file_manager/path_util.h"
20 #include "chrome/browser/extensions/component_loader.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h"
23 #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h"
24 #include "chrome/browser/ui/ash/holding_space/holding_space_util.h"
25 #include "chromeos/dbus/session_manager/session_manager_client.h"
26 #include "components/session_manager/core/session_manager.h"
27 #include "components/session_manager/core/session_manager_observer.h"
28 #include "storage/browser/file_system/external_mount_points.h"
29 #include "ui/gfx/image/image_skia.h"
30 #include "ui/views/view.h"
31 
32 namespace ash {
33 
34 namespace {
35 
36 // Helpers ---------------------------------------------------------------------
37 
38 // Returns the path of the downloads mount point for the given `profile`.
GetDownloadsPath(Profile * profile)39 base::FilePath GetDownloadsPath(Profile* profile) {
40   base::FilePath result;
41   EXPECT_TRUE(
42       storage::ExternalMountPoints::GetSystemInstance()->GetRegisteredPath(
43           file_manager::util::GetDownloadsMountPointName(profile), &result));
44   return result;
45 }
46 
47 // Creates a file at the root of the downloads mount point with the specified
48 // `extension`, returning the path of the created file.
CreateFile(Profile * profile,const std::string & extension)49 base::FilePath CreateFile(Profile* profile, const std::string& extension) {
50   const base::FilePath file_path =
51       GetDownloadsPath(profile).Append(base::StringPrintf(
52           "%s.%s", base::UnguessableToken::Create().ToString().c_str(),
53           extension.c_str()));
54 
55   {
56     base::ScopedAllowBlockingForTesting allow_blocking;
57     if (!base::CreateDirectory(file_path.DirName())) {
58       ADD_FAILURE() << "Failed to create parent directory.";
59       return base::FilePath();
60     }
61     if (!base::WriteFile(file_path, /*content=*/std::string())) {
62       ADD_FAILURE() << "Filed to write file contents.";
63       return base::FilePath();
64     }
65   }
66 
67   return file_path;
68 }
69 
70 // Creates a .txt file at the root of the downloads mount point and returns the
71 // path of the created file.
CreateTextFile(Profile * profile)72 base::FilePath CreateTextFile(Profile* profile) {
73   return CreateFile(profile, "txt");
74 }
75 
76 // Creates a .png file at the root of the downloads mount point and returns the
77 // path of the created file.
CreateImageFile(Profile * profile)78 base::FilePath CreateImageFile(Profile* profile) {
79   return CreateFile(profile, "png");
80 }
81 
82 // SessionStateWaiter ----------------------------------------------------------
83 
84 // Utility class which allows waiting for a `session_manager::SessionState`.
85 class SessionStateWaiter : public session_manager::SessionManagerObserver {
86  public:
SessionStateWaiter()87   SessionStateWaiter() {
88     session_manager_observer_.Add(session_manager::SessionManager::Get());
89   }
90 
WaitFor(session_manager::SessionState state)91   void WaitFor(session_manager::SessionState state) {
92     if (session_state() == state)
93       return;
94 
95     state_ = state;
96 
97     wait_loop_ = std::make_unique<base::RunLoop>();
98     wait_loop_->Run();
99     wait_loop_.reset();
100   }
101 
102  private:
103   // session_manager::SessionManagerObserver:
OnSessionStateChanged()104   void OnSessionStateChanged() override {
105     if (wait_loop_ && session_state() == state_)
106       wait_loop_->Quit();
107   }
108 
session_state() const109   session_manager::SessionState session_state() const {
110     return session_manager::SessionManager::Get()->session_state();
111   }
112 
113   session_manager::SessionState state_ = session_manager::SessionState::UNKNOWN;
114   std::unique_ptr<base::RunLoop> wait_loop_;
115 
116   ScopedObserver<session_manager::SessionManager,
117                  session_manager::SessionManagerObserver>
118       session_manager_observer_{this};
119 };
120 
121 }  // namespace
122 
123 // HoldingSpaceBrowserTestBase -------------------------------------------------
124 
HoldingSpaceBrowserTestBase()125 HoldingSpaceBrowserTestBase::HoldingSpaceBrowserTestBase() {
126   scoped_feature_list_.InitAndEnableFeature(features::kTemporaryHoldingSpace);
127 }
128 
129 HoldingSpaceBrowserTestBase::~HoldingSpaceBrowserTestBase() = default;
130 
SetUpInProcessBrowserTestFixture()131 void HoldingSpaceBrowserTestBase::SetUpInProcessBrowserTestFixture() {
132   InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
133   extensions::ComponentLoader::EnableBackgroundExtensionsForTesting();
134 }
135 
SetUpOnMainThread()136 void HoldingSpaceBrowserTestBase::SetUpOnMainThread() {
137   InProcessBrowserTest::SetUpOnMainThread();
138   test_api_ = std::make_unique<HoldingSpaceTestApi>();
139 }
140 
141 // static
GetRootWindowForNewWindows()142 aura::Window* HoldingSpaceBrowserTestBase::GetRootWindowForNewWindows() {
143   return HoldingSpaceTestApi::GetRootWindowForNewWindows();
144 }
145 
GetProfile()146 Profile* HoldingSpaceBrowserTestBase::GetProfile() {
147   return ProfileManager::GetActiveUserProfile();
148 }
149 
Show()150 void HoldingSpaceBrowserTestBase::Show() {
151   test_api_->Show();
152 }
153 
Close()154 void HoldingSpaceBrowserTestBase::Close() {
155   test_api_->Close();
156 }
157 
IsShowing()158 bool HoldingSpaceBrowserTestBase::IsShowing() {
159   return test_api_->IsShowing();
160 }
161 
IsShowingInShelf()162 bool HoldingSpaceBrowserTestBase::IsShowingInShelf() {
163   return test_api_->IsShowingInShelf();
164 }
165 
AddDownloadFile()166 HoldingSpaceItem* HoldingSpaceBrowserTestBase::AddDownloadFile() {
167   return AddItem(GetProfile(), HoldingSpaceItem::Type::kDownload,
168                  /*file_path=*/CreateTextFile(GetProfile()));
169 }
170 
AddNearbyShareFile()171 HoldingSpaceItem* HoldingSpaceBrowserTestBase::AddNearbyShareFile() {
172   return AddItem(GetProfile(), HoldingSpaceItem::Type::kNearbyShare,
173                  /*file_path=*/CreateImageFile(GetProfile()));
174 }
175 
AddPinnedFile()176 HoldingSpaceItem* HoldingSpaceBrowserTestBase::AddPinnedFile() {
177   return AddItem(GetProfile(), HoldingSpaceItem::Type::kPinnedFile,
178                  /*file_path=*/CreateTextFile(GetProfile()));
179 }
180 
AddScreenshotFile()181 HoldingSpaceItem* HoldingSpaceBrowserTestBase::AddScreenshotFile() {
182   return AddItem(GetProfile(), HoldingSpaceItem::Type::kScreenshot,
183                  /*file_path=*/CreateImageFile(GetProfile()));
184 }
185 
AddScreenRecordingFile()186 HoldingSpaceItem* HoldingSpaceBrowserTestBase::AddScreenRecordingFile() {
187   return AddItem(GetProfile(), HoldingSpaceItem::Type::kScreenRecording,
188                  /*file_path=*/CreateImageFile(GetProfile()));
189 }
190 
AddItem(Profile * profile,HoldingSpaceItem::Type type,const base::FilePath & file_path)191 HoldingSpaceItem* HoldingSpaceBrowserTestBase::AddItem(
192     Profile* profile,
193     HoldingSpaceItem::Type type,
194     const base::FilePath& file_path) {
195   auto item = HoldingSpaceItem::CreateFileBackedItem(
196       type, file_path,
197       holding_space_util::ResolveFileSystemUrl(profile, file_path),
198       /*image=*/
199       std::make_unique<HoldingSpaceImage>(
200           /*placeholder=*/gfx::ImageSkia(),
201           /*async_bitmap_resolver=*/base::DoNothing()));
202 
203   auto* item_ptr = item.get();
204 
205   // Add holding space items through the holding space keyed service so that the
206   // time of first add will be marked in preferences. The time of first add
207   // contributes to deciding when the holding space tray is visible.
208   HoldingSpaceKeyedServiceFactory::GetInstance()
209       ->GetService(GetProfile())
210       ->AddItem(std::move(item));
211 
212   return item_ptr;
213 }
214 
RemoveItem(const HoldingSpaceItem * item)215 void HoldingSpaceBrowserTestBase::RemoveItem(const HoldingSpaceItem* item) {
216   HoldingSpaceController::Get()->model()->RemoveItem(item->id());
217 }
218 
GetDownloadChips()219 std::vector<views::View*> HoldingSpaceBrowserTestBase::GetDownloadChips() {
220   return test_api_->GetDownloadChips();
221 }
222 
GetPinnedFileChips()223 std::vector<views::View*> HoldingSpaceBrowserTestBase::GetPinnedFileChips() {
224   return test_api_->GetPinnedFileChips();
225 }
226 
GetScreenCaptureViews()227 std::vector<views::View*> HoldingSpaceBrowserTestBase::GetScreenCaptureViews() {
228   return test_api_->GetScreenCaptureViews();
229 }
230 
GetTrayIcon()231 views::View* HoldingSpaceBrowserTestBase::GetTrayIcon() {
232   return test_api_->GetTrayIcon();
233 }
234 
RequestAndAwaitLockScreen()235 void HoldingSpaceBrowserTestBase::RequestAndAwaitLockScreen() {
236   if (session_manager::SessionManager::Get()->IsScreenLocked())
237     return;
238 
239   chromeos::SessionManagerClient::Get()->RequestLockScreen();
240   SessionStateWaiter().WaitFor(session_manager::SessionState::LOCKED);
241 }
242 
243 }  // namespace ash
244