Disable TabDragController tests that fail with a real compositor.
[chromium-blink-merge.git] / chrome / browser / ui / ash / screenshot_taker.cc
blobfecec918ba14100dff910c5d35534043711133bf
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/ash/screenshot_taker.h"
7 #include <climits>
8 #include <string>
10 #include "ash/shell.h"
11 #include "ash/system/system_notifier.h"
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/file_util.h"
15 #include "base/i18n/time_formatting.h"
16 #include "base/logging.h"
17 #include "base/memory/ref_counted_memory.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/threading/sequenced_worker_pool.h"
22 #include "base/time/time.h"
23 #include "chrome/browser/browser_process.h"
24 #include "chrome/browser/download/download_prefs.h"
25 #include "chrome/browser/notifications/notification_ui_manager.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/profiles/profile_manager.h"
28 #include "chrome/common/pref_names.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/user_metrics.h"
31 #include "grit/ash_strings.h"
32 #include "grit/theme_resources.h"
33 #include "grit/ui_strings.h"
34 #include "ui/aura/root_window.h"
35 #include "ui/aura/window.h"
36 #include "ui/base/clipboard/clipboard.h"
37 #include "ui/base/clipboard/scoped_clipboard_writer.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/base/resource/resource_bundle.h"
40 #include "ui/gfx/image/image.h"
41 #include "ui/snapshot/snapshot.h"
43 #if defined(USE_ASH)
44 #include "ash/shell.h"
45 #include "ash/shell_delegate.h"
46 #endif
48 #if defined(OS_CHROMEOS)
49 #include "chrome/browser/chromeos/drive/file_system_interface.h"
50 #include "chrome/browser/chromeos/drive/file_system_util.h"
51 #include "chrome/browser/chromeos/file_manager/open_util.h"
52 #include "chrome/browser/chromeos/login/user_manager.h"
53 #include "chrome/browser/notifications/desktop_notification_service.h"
54 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
55 #include "chromeos/login/login_state.h"
56 #endif
58 namespace {
59 // The minimum interval between two screenshot commands. It has to be
60 // more than 1000 to prevent the conflict of filenames.
61 const int kScreenshotMinimumIntervalInMS = 1000;
63 const char kNotificationId[] = "screenshot";
65 const char kNotificationOriginUrl[] = "chrome://screenshot";
67 const char kImageClipboardFormatPrefix[] = "<img src='data:image/png;base64,";
68 const char kImageClipboardFormatSuffix[] = "'>";
70 void CopyScreenshotToClipboard(scoped_refptr<base::RefCountedString> png_data) {
71 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
73 std::string encoded;
74 base::Base64Encode(png_data->data(), &encoded);
76 // Only cares about HTML because ChromeOS doesn't need other formats.
77 // TODO(dcheng): Why don't we take advantage of the ability to write bitmaps
78 // to the clipboard here?
80 ui::ScopedClipboardWriter scw(ui::Clipboard::GetForCurrentThread(),
81 ui::CLIPBOARD_TYPE_COPY_PASTE);
82 std::string html(kImageClipboardFormatPrefix);
83 html += encoded;
84 html += kImageClipboardFormatSuffix;
85 scw.WriteHTML(base::UTF8ToUTF16(html), std::string());
87 content::RecordAction(base::UserMetricsAction("Screenshot_CopyClipboard"));
90 void ReadFileAndCopyToClipboardLocal(const base::FilePath& screenshot_path) {
91 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
93 scoped_refptr<base::RefCountedString> png_data(new base::RefCountedString());
94 if (!base::ReadFileToString(screenshot_path, &(png_data->data()))) {
95 LOG(ERROR) << "Failed to read the screenshot file: "
96 << screenshot_path.value();
97 return;
100 content::BrowserThread::PostTask(
101 content::BrowserThread::UI, FROM_HERE,
102 base::Bind(CopyScreenshotToClipboard, png_data));
105 #if defined(OS_CHROMEOS)
106 void ReadFileAndCopyToClipboardDrive(drive::FileError error,
107 const base::FilePath& file_path,
108 scoped_ptr<drive::ResourceEntry> entry) {
109 if (error != drive::FILE_ERROR_OK) {
110 LOG(ERROR) << "Failed to read the screenshot path on drive: "
111 << drive::FileErrorToString(error);
112 return;
114 content::BrowserThread::GetBlockingPool()->PostTask(
115 FROM_HERE,
116 base::Bind(&ReadFileAndCopyToClipboardLocal, file_path));
118 #endif
120 // Delegate for a notification. This class has two roles: to implement callback
121 // methods for notification, and to provide an identity of the associated
122 // notification.
123 class ScreenshotTakerNotificationDelegate : public NotificationDelegate {
124 public:
125 ScreenshotTakerNotificationDelegate(bool success,
126 Profile* profile,
127 const base::FilePath& screenshot_path)
128 : success_(success),
129 profile_(profile),
130 screenshot_path_(screenshot_path) {
133 // Overridden from NotificationDelegate:
134 virtual void Display() OVERRIDE {}
135 virtual void Error() OVERRIDE {}
136 virtual void Close(bool by_user) OVERRIDE {}
137 virtual void Click() OVERRIDE {
138 if (!success_)
139 return;
140 #if defined(OS_CHROMEOS)
141 file_manager::util::ShowItemInFolder(profile_, screenshot_path_);
142 #else
143 // TODO(sschmitz): perhaps add similar action for Windows.
144 #endif
146 virtual void ButtonClick(int button_index) OVERRIDE {
147 DCHECK(success_ && button_index == 0);
149 // To avoid keeping the screenshot image on memory, it will re-read the
150 // screenshot file and copy it to the clipboard.
151 #if defined(OS_CHROMEOS)
152 if (drive::util::IsUnderDriveMountPoint(screenshot_path_)) {
153 drive::FileSystemInterface* file_system =
154 drive::util::GetFileSystemByProfile(profile_);
155 file_system->GetFile(
156 drive::util::ExtractDrivePath(screenshot_path_),
157 base::Bind(&ReadFileAndCopyToClipboardDrive));
158 return;
160 #endif
161 content::BrowserThread::GetBlockingPool()->PostTask(
162 FROM_HERE, base::Bind(
163 &ReadFileAndCopyToClipboardLocal, screenshot_path_));
165 virtual bool HasClickedListener() OVERRIDE { return success_; }
166 virtual std::string id() const OVERRIDE {
167 return std::string(kNotificationId);
169 virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
170 return NULL;
173 private:
174 virtual ~ScreenshotTakerNotificationDelegate() {}
176 const bool success_;
177 Profile* profile_;
178 const base::FilePath screenshot_path_;
180 DISALLOW_COPY_AND_ASSIGN(ScreenshotTakerNotificationDelegate);
183 typedef base::Callback<
184 void(ScreenshotTakerObserver::Result screenshot_result,
185 const base::FilePath& screenshot_path)> ShowNotificationCallback;
187 void SaveScreenshotInternal(const ShowNotificationCallback& callback,
188 const base::FilePath& screenshot_path,
189 const base::FilePath& local_path,
190 scoped_refptr<base::RefCountedBytes> png_data) {
191 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
192 DCHECK(!local_path.empty());
193 ScreenshotTakerObserver::Result result =
194 ScreenshotTakerObserver::SCREENSHOT_SUCCESS;
195 if (static_cast<size_t>(file_util::WriteFile(
196 local_path,
197 reinterpret_cast<char*>(&(png_data->data()[0])),
198 png_data->size())) != png_data->size()) {
199 LOG(ERROR) << "Failed to save to " << local_path.value();
200 result = ScreenshotTakerObserver::SCREENSHOT_WRITE_FILE_FAILED;
202 content::BrowserThread::PostTask(
203 content::BrowserThread::UI, FROM_HERE,
204 base::Bind(callback, result, screenshot_path));
207 void SaveScreenshot(const ShowNotificationCallback& callback,
208 const base::FilePath& screenshot_path,
209 scoped_refptr<base::RefCountedBytes> png_data) {
210 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
211 DCHECK(!screenshot_path.empty());
213 if (!base::CreateDirectory(screenshot_path.DirName())) {
214 LOG(ERROR) << "Failed to ensure the existence of "
215 << screenshot_path.DirName().value();
216 content::BrowserThread::PostTask(
217 content::BrowserThread::UI, FROM_HERE,
218 base::Bind(callback,
219 ScreenshotTakerObserver::SCREENSHOT_CREATE_DIR_FAILED,
220 screenshot_path));
221 return;
223 SaveScreenshotInternal(callback, screenshot_path, screenshot_path, png_data);
226 // TODO(kinaba): crbug.com/140425, remove this ungly #ifdef dispatch.
227 #if defined(OS_CHROMEOS)
228 void SaveScreenshotToDrive(const ShowNotificationCallback& callback,
229 const base::FilePath& screenshot_path,
230 scoped_refptr<base::RefCountedBytes> png_data,
231 drive::FileError error,
232 const base::FilePath& local_path) {
233 // |screenshot_path| is used in the notification callback.
234 // |local_path| is a temporary file in a hidden cache directory used for
235 // internal work generated by drive::util::PrepareWritableFileAndRun.
236 if (error != drive::FILE_ERROR_OK) {
237 LOG(ERROR) << "Failed to write screenshot image to Google Drive: " << error;
238 content::BrowserThread::PostTask(
239 content::BrowserThread::UI, FROM_HERE,
240 base::Bind(callback,
241 ScreenshotTakerObserver::SCREENSHOT_CREATE_FILE_FAILED,
242 screenshot_path));
243 return;
245 SaveScreenshotInternal(callback, screenshot_path, local_path, png_data);
248 void EnsureDirectoryExistsCallback(
249 const ShowNotificationCallback& callback,
250 Profile* profile,
251 const base::FilePath& screenshot_path,
252 scoped_refptr<base::RefCountedBytes> png_data,
253 drive::FileError error) {
254 // It is okay to fail with FILE_ERROR_EXISTS since anyway the directory
255 // of the target file exists.
256 if (error == drive::FILE_ERROR_OK ||
257 error == drive::FILE_ERROR_EXISTS) {
258 drive::util::PrepareWritableFileAndRun(
259 profile,
260 screenshot_path,
261 base::Bind(&SaveScreenshotToDrive,
262 callback,
263 screenshot_path,
264 png_data));
265 } else {
266 LOG(ERROR) << "Failed to ensure the existence of the specified directory "
267 << "in Google Drive: " << error;
268 callback.Run(ScreenshotTakerObserver::SCREENSHOT_CHECK_DIR_FAILED,
269 screenshot_path);
273 void PostSaveScreenshotTask(const ShowNotificationCallback& callback,
274 Profile* profile,
275 const base::FilePath& screenshot_path,
276 scoped_refptr<base::RefCountedBytes> png_data) {
277 if (drive::util::IsUnderDriveMountPoint(screenshot_path)) {
278 drive::util::EnsureDirectoryExists(
279 profile,
280 screenshot_path.DirName(),
281 base::Bind(&EnsureDirectoryExistsCallback,
282 callback,
283 profile,
284 screenshot_path,
285 png_data));
286 } else {
287 content::BrowserThread::GetBlockingPool()->PostTask(
288 FROM_HERE, base::Bind(&SaveScreenshot,
289 callback,
290 screenshot_path,
291 png_data));
294 #else
295 void PostSaveScreenshotTask(const ShowNotificationCallback& callback,
296 Profile* profile,
297 const base::FilePath& screenshot_path,
298 scoped_refptr<base::RefCountedBytes> png_data) {
299 content::BrowserThread::GetBlockingPool()->PostTask(
300 FROM_HERE, base::Bind(&SaveScreenshot,
301 callback,
302 screenshot_path,
303 png_data));
305 #endif
307 bool ShouldUse24HourClock() {
308 #if defined(OS_CHROMEOS)
309 Profile* profile = ProfileManager::GetActiveUserProfile();
310 if (profile) {
311 return profile->GetPrefs()->GetBoolean(prefs::kUse24HourClock);
313 #endif
314 return base::GetHourClockType() == base::k24HourClock;
317 std::string GetScreenshotBaseFilename() {
318 base::Time::Exploded now;
319 base::Time::Now().LocalExplode(&now);
321 // We don't use base/i18n/time_formatting.h here because it doesn't
322 // support our format. Don't use ICU either to avoid i18n file names
323 // for non-English locales.
324 // TODO(mukai): integrate this logic somewhere time_formatting.h
325 std::string file_name = base::StringPrintf(
326 "Screenshot %d-%02d-%02d at ", now.year, now.month, now.day_of_month);
328 if (ShouldUse24HourClock()) {
329 file_name.append(base::StringPrintf(
330 "%02d.%02d.%02d", now.hour, now.minute, now.second));
331 } else {
332 int hour = now.hour;
333 if (hour > 12) {
334 hour -= 12;
335 } else if (hour == 0) {
336 hour = 12;
338 file_name.append(base::StringPrintf(
339 "%d.%02d.%02d ", hour, now.minute, now.second));
340 file_name.append((now.hour >= 12) ? "PM" : "AM");
343 return file_name;
346 bool GetScreenshotDirectory(base::FilePath* directory) {
347 bool is_logged_in = true;
349 #if defined(OS_CHROMEOS)
350 is_logged_in = chromeos::LoginState::Get()->IsUserLoggedIn();
351 #endif
353 if (is_logged_in) {
354 DownloadPrefs* download_prefs = DownloadPrefs::FromBrowserContext(
355 ProfileManager::GetActiveUserProfile());
356 *directory = download_prefs->DownloadPath();
357 } else {
358 if (!base::GetTempDir(directory)) {
359 LOG(ERROR) << "Failed to find temporary directory.";
360 return false;
363 return true;
366 const int GetScreenshotNotificationTitle(
367 ScreenshotTakerObserver::Result screenshot_result) {
368 switch (screenshot_result) {
369 case ScreenshotTakerObserver::SCREENSHOTS_DISABLED:
370 return IDS_ASH_SCREENSHOT_NOTIFICATION_TITLE_DISABLED;
371 case ScreenshotTakerObserver::SCREENSHOT_SUCCESS:
372 return IDS_ASH_SCREENSHOT_NOTIFICATION_TITLE_SUCCESS;
373 default:
374 return IDS_ASH_SCREENSHOT_NOTIFICATION_TITLE_FAIL;
378 const int GetScreenshotNotificationText(
379 ScreenshotTakerObserver::Result screenshot_result) {
380 switch (screenshot_result) {
381 case ScreenshotTakerObserver::SCREENSHOTS_DISABLED:
382 return IDS_ASH_SCREENSHOT_NOTIFICATION_TEXT_DISABLED;
383 case ScreenshotTakerObserver::SCREENSHOT_SUCCESS:
384 return IDS_ASH_SCREENSHOT_NOTIFICATION_TEXT_SUCCESS;
385 default:
386 return IDS_ASH_SCREENSHOT_NOTIFICATION_TEXT_FAIL;
390 } // namespace
392 ScreenshotTaker::ScreenshotTaker()
393 : factory_(this),
394 profile_for_test_(NULL) {
397 ScreenshotTaker::~ScreenshotTaker() {
400 void ScreenshotTaker::HandleTakeScreenshotForAllRootWindows() {
401 if (g_browser_process->local_state()->
402 GetBoolean(prefs::kDisableScreenshots)) {
403 ShowNotification(ScreenshotTakerObserver::SCREENSHOTS_DISABLED,
404 base::FilePath());
405 return;
407 base::FilePath screenshot_directory;
408 if (!screenshot_directory_for_test_.empty()) {
409 screenshot_directory = screenshot_directory_for_test_;
410 } else if (!GetScreenshotDirectory(&screenshot_directory)) {
411 ShowNotification(ScreenshotTakerObserver::SCREENSHOT_GET_DIR_FAILED,
412 base::FilePath());
413 return;
415 std::string screenshot_basename = !screenshot_basename_for_test_.empty() ?
416 screenshot_basename_for_test_ : GetScreenshotBaseFilename();
418 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
419 // Reorder root_windows to take the primary root window's snapshot at first.
420 aura::Window* primary_root = ash::Shell::GetPrimaryRootWindow();
421 if (*(root_windows.begin()) != primary_root) {
422 root_windows.erase(std::find(
423 root_windows.begin(), root_windows.end(), primary_root));
424 root_windows.insert(root_windows.begin(), primary_root);
426 for (size_t i = 0; i < root_windows.size(); ++i) {
427 aura::Window* root_window = root_windows[i];
428 std::string basename = screenshot_basename;
429 gfx::Rect rect = root_window->bounds();
430 if (root_windows.size() > 1)
431 basename += base::StringPrintf(" - Display %d", static_cast<int>(i + 1));
432 base::FilePath screenshot_path =
433 screenshot_directory.AppendASCII(basename + ".png");
434 GrabFullWindowSnapshotAsync(
435 root_window, rect, GetProfile(), screenshot_path, i);
437 content::RecordAction(base::UserMetricsAction("Screenshot_TakeFull"));
440 void ScreenshotTaker::HandleTakePartialScreenshot(
441 aura::Window* window, const gfx::Rect& rect) {
442 if (g_browser_process->local_state()->
443 GetBoolean(prefs::kDisableScreenshots)) {
444 ShowNotification(ScreenshotTakerObserver::SCREENSHOTS_DISABLED,
445 base::FilePath());
446 return;
448 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
450 base::FilePath screenshot_directory;
451 if (!screenshot_directory_for_test_.empty()) {
452 screenshot_directory = screenshot_directory_for_test_;
453 } else if (!GetScreenshotDirectory(&screenshot_directory)) {
454 ShowNotification(ScreenshotTakerObserver::SCREENSHOT_GET_DIR_FAILED,
455 base::FilePath());
456 return;
459 std::string screenshot_basename = !screenshot_basename_for_test_.empty() ?
460 screenshot_basename_for_test_ : GetScreenshotBaseFilename();
461 base::FilePath screenshot_path =
462 screenshot_directory.AppendASCII(screenshot_basename + ".png");
463 GrabPartialWindowSnapshotAsync(window, rect, GetProfile(), screenshot_path);
464 content::RecordAction(base::UserMetricsAction("Screenshot_TakePartial"));
467 bool ScreenshotTaker::CanTakeScreenshot() {
468 return last_screenshot_timestamp_.is_null() ||
469 base::Time::Now() - last_screenshot_timestamp_ >
470 base::TimeDelta::FromMilliseconds(
471 kScreenshotMinimumIntervalInMS);
474 Notification* ScreenshotTaker::CreateNotification(
475 ScreenshotTakerObserver::Result screenshot_result,
476 const base::FilePath& screenshot_path) {
477 const std::string notification_id(kNotificationId);
478 // We cancel a previous screenshot notification, if any, to ensure we get
479 // a fresh notification pop-up.
480 g_browser_process->notification_ui_manager()->CancelById(notification_id);
481 const base::string16 replace_id(base::UTF8ToUTF16(notification_id));
482 bool success =
483 (screenshot_result == ScreenshotTakerObserver::SCREENSHOT_SUCCESS);
484 message_center::RichNotificationData optional_field;
485 if (success) {
486 const base::string16 label = l10n_util::GetStringUTF16(
487 IDS_MESSAGE_CENTER_NOTIFICATION_BUTTON_COPY_SCREENSHOT_TO_CLIPBOARD);
488 optional_field.buttons.push_back(message_center::ButtonInfo(label));
490 return new Notification(
491 message_center::NOTIFICATION_TYPE_SIMPLE,
492 GURL(kNotificationOriginUrl),
493 l10n_util::GetStringUTF16(
494 GetScreenshotNotificationTitle(screenshot_result)),
495 l10n_util::GetStringUTF16(
496 GetScreenshotNotificationText(screenshot_result)),
497 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
498 IDR_SCREENSHOT_NOTIFICATION_ICON),
499 blink::WebTextDirectionDefault,
500 message_center::NotifierId(
501 message_center::NotifierId::SYSTEM_COMPONENT,
502 ash::system_notifier::kNotifierScreenshot),
503 l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_NOTIFIER_SCREENSHOT_NAME),
504 replace_id,
505 optional_field,
506 new ScreenshotTakerNotificationDelegate(
507 success, GetProfile(), screenshot_path));
510 void ScreenshotTaker::ShowNotification(
511 ScreenshotTakerObserver::Result screenshot_result,
512 const base::FilePath& screenshot_path) {
513 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
514 #if defined(OS_CHROMEOS)
515 // Do not show a notification that a screenshot was taken while no user is
516 // logged in, since it is confusing for the user to get a message about it
517 // after he logs in (crbug.com/235217).
518 if (!chromeos::LoginState::Get()->IsUserLoggedIn())
519 return;
521 // TODO(sschmitz): make this work for Windows.
522 DesktopNotificationService* const service =
523 DesktopNotificationServiceFactory::GetForProfile(GetProfile());
524 if (service->IsNotifierEnabled(message_center::NotifierId(
525 message_center::NotifierId::SYSTEM_COMPONENT,
526 ash::system_notifier::kNotifierScreenshot))) {
527 scoped_ptr<Notification> notification(
528 CreateNotification(screenshot_result, screenshot_path));
529 g_browser_process->notification_ui_manager()->Add(*notification,
530 GetProfile());
532 #endif
533 FOR_EACH_OBSERVER(ScreenshotTakerObserver, observers_,
534 OnScreenshotCompleted(screenshot_result, screenshot_path));
537 void ScreenshotTaker::AddObserver(ScreenshotTakerObserver* observer) {
538 observers_.AddObserver(observer);
541 void ScreenshotTaker::RemoveObserver(ScreenshotTakerObserver* observer) {
542 observers_.RemoveObserver(observer);
545 bool ScreenshotTaker::HasObserver(ScreenshotTakerObserver* observer) const {
546 return observers_.HasObserver(observer);
549 void ScreenshotTaker::GrabWindowSnapshotAsyncCallback(
550 base::FilePath screenshot_path,
551 bool is_partial,
552 int window_idx,
553 scoped_refptr<base::RefCountedBytes> png_data) {
554 if (!png_data) {
555 if (is_partial) {
556 LOG(ERROR) << "Failed to grab the window screenshot";
557 ShowNotification(
558 ScreenshotTakerObserver::SCREENSHOT_GRABWINDOW_PARTIAL_FAILED,
559 screenshot_path);
560 } else {
561 LOG(ERROR) << "Failed to grab the window screenshot for " << window_idx;
562 ShowNotification(
563 ScreenshotTakerObserver::SCREENSHOT_GRABWINDOW_FULL_FAILED,
564 screenshot_path);
566 return;
569 PostSaveScreenshotTask(
570 base::Bind(&ScreenshotTaker::ShowNotification, factory_.GetWeakPtr()),
571 GetProfile(),
572 screenshot_path,
573 png_data);
576 void ScreenshotTaker::GrabPartialWindowSnapshotAsync(
577 aura::Window* window,
578 const gfx::Rect& snapshot_bounds,
579 Profile* profile,
580 base::FilePath screenshot_path) {
581 last_screenshot_timestamp_ = base::Time::Now();
583 bool is_partial = true;
584 int window_idx = -1; // unused
585 ui::GrabWindowSnapshotAsync(
586 window,
587 snapshot_bounds,
588 content::BrowserThread::GetBlockingPool(),
589 base::Bind(&ScreenshotTaker::GrabWindowSnapshotAsyncCallback,
590 factory_.GetWeakPtr(),
591 screenshot_path,
592 is_partial,
593 window_idx));
596 void ScreenshotTaker::GrabFullWindowSnapshotAsync(
597 aura::Window* window,
598 const gfx::Rect& snapshot_bounds,
599 Profile* profile,
600 base::FilePath screenshot_path,
601 int window_idx) {
602 last_screenshot_timestamp_ = base::Time::Now();
604 bool is_partial = false;
605 ui::GrabWindowSnapshotAsync(
606 window,
607 snapshot_bounds,
608 content::BrowserThread::GetBlockingPool(),
609 base::Bind(&ScreenshotTaker::GrabWindowSnapshotAsyncCallback,
610 factory_.GetWeakPtr(),
611 screenshot_path,
612 is_partial,
613 window_idx));
616 Profile* ScreenshotTaker::GetProfile() {
617 if (profile_for_test_)
618 return profile_for_test_;
619 return ProfileManager::GetActiveUserProfile();
622 void ScreenshotTaker::SetScreenshotDirectoryForTest(
623 const base::FilePath& directory) {
624 screenshot_directory_for_test_ = directory;
627 void ScreenshotTaker::SetScreenshotBasenameForTest(
628 const std::string& basename) {
629 screenshot_basename_for_test_ = basename;
632 void ScreenshotTaker::SetScreenshotProfileForTest(Profile* profile) {
633 profile_for_test_ = profile;