Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(452)

Unified Diff: chrome/browser/ui/ash/screenshot_taker.cc

Issue 13105002: Screenshot effect non-obvious (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: update Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/ash/screenshot_taker.cc
diff --git a/chrome/browser/ui/ash/screenshot_taker.cc b/chrome/browser/ui/ash/screenshot_taker.cc
index e5742f9dd8a57d100c2a75de28dde8fcefa44d0c..57f6007b028f1129e96c1380c76b200b57dcc8a9 100644
--- a/chrome/browser/ui/ash/screenshot_taker.cc
+++ b/chrome/browser/ui/ash/screenshot_taker.cc
@@ -8,24 +8,30 @@
#include <string>
#include "ash/shell.h"
-#include "ash/shell_delegate.h"
-#include "ash/shell_window_ids.h"
#include "base/bind.h"
#include "base/file_util.h"
-#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/stringprintf.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/extensions/file_manager_util.h"
#include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/webui/screenshot_source.h"
#include "chrome/browser/ui/window_snapshot/window_snapshot.h"
#include "content/public/browser/browser_thread.h"
+#include "grit/ash_strings.h"
+#include "grit/theme_resources.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/drive/drive_file_system_util.h"
@@ -33,31 +39,87 @@
#endif
namespace {
-// How opaque should the layer that we flash onscreen to provide visual
-// feedback after the screenshot is taken be?
-const float kVisualFeedbackLayerOpacity = 0.25f;
-
-// How long should the visual feedback layer be displayed?
-const int64 kVisualFeedbackLayerDisplayTimeMs = 100;
-
// The minimum interval between two screenshot commands. It has to be
// more than 1000 to prevent the conflict of filenames.
const int kScreenshotMinimumIntervalInMS = 1000;
+const char kNotificationOriginUrl[] = "chrome://screenshot";
+
+// Delegate for a notification. This class has two roles: to implement callback
+// methods for notification, and to provide an identity of the associated
+// notification.
+class ScreenshotTakerNotificationDelegate : public NotificationDelegate {
+ public:
+ ScreenshotTakerNotificationDelegate(const std::string& id_text,
+ bool success,
+ const base::FilePath& screenshot_path)
+ : id_text_(id_text),
+ success_(success),
+ screenshot_path_(screenshot_path) {
+ }
+
+ // Overridden from NotificationDelegate:
+ virtual void Display() OVERRIDE {}
+ virtual void Error() OVERRIDE {}
+ virtual void Close(bool by_user) OVERRIDE {}
+ virtual void Click() OVERRIDE {
+ if (success_)
+ file_manager_util::ShowFileInFolder(screenshot_path_);
+ }
+ virtual std::string id() const OVERRIDE { return id_text_; }
+ virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
+ return NULL;
+ }
+
+ private:
+ virtual ~ScreenshotTakerNotificationDelegate() {}
+
+ const std::string id_text_;
+ const bool success_;
+ const base::FilePath screenshot_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenshotTakerNotificationDelegate);
+};
+
+void ShowNotificationCaller(base::WeakPtr<ScreenshotTaker> screenshot_taker,
+ ScreenshotTakerObserver::Result screenshot_result,
+ const base::FilePath& screenshot_path) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (screenshot_taker.get())
+ screenshot_taker->ShowNotification(screenshot_result, screenshot_path);
+}
+
+void PostShowNotification(base::WeakPtr<ScreenshotTaker> screenshot_taker,
+ ScreenshotTakerObserver::Result screenshot_result,
+ const base::FilePath& screenshot_path) {
+ DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&ShowNotificationCaller,
+ screenshot_taker,
+ screenshot_result,
+ screenshot_path));
+}
-void SaveScreenshotInternal(const base::FilePath& screenshot_path,
+void SaveScreenshotInternal(base::WeakPtr<ScreenshotTaker> screenshot_taker,
+ const base::FilePath& screenshot_path,
scoped_refptr<base::RefCountedBytes> png_data) {
DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
DCHECK(!screenshot_path.empty());
+ ScreenshotTakerObserver::Result result =
+ ScreenshotTakerObserver::SCREENSHOT_SUCCESS;
if (static_cast<size_t>(file_util::WriteFile(
screenshot_path,
reinterpret_cast<char*>(&(png_data->data()[0])),
png_data->size())) != png_data->size()) {
LOG(ERROR) << "Failed to save to " << screenshot_path.value();
+ result = ScreenshotTakerObserver::SCREENSHOT_WRITE_FILE_FAILED;
}
+ PostShowNotification(screenshot_taker, result, screenshot_path);
}
-void SaveScreenshot(const base::FilePath& screenshot_path,
+void SaveScreenshot(base::WeakPtr<ScreenshotTaker> screenshot_taker,
+ const base::FilePath& screenshot_path,
scoped_refptr<base::RefCountedBytes> png_data) {
DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
DCHECK(!screenshot_path.empty());
@@ -65,24 +127,34 @@ void SaveScreenshot(const base::FilePath& screenshot_path,
if (!file_util::CreateDirectory(screenshot_path.DirName())) {
LOG(ERROR) << "Failed to ensure the existence of "
<< screenshot_path.DirName().value();
+ PostShowNotification(
+ screenshot_taker,
+ ScreenshotTakerObserver::SCREENSHOT_CREATE_DIR_FAILED,
+ screenshot_path);
return;
}
- SaveScreenshotInternal(screenshot_path, png_data);
+ SaveScreenshotInternal(screenshot_taker, screenshot_path, png_data);
}
// TODO(kinaba): crbug.com/140425, remove this ungly #ifdef dispatch.
#if defined(OS_CHROMEOS)
-void SaveScreenshotToDrive(scoped_refptr<base::RefCountedBytes> png_data,
+void SaveScreenshotToDrive(base::WeakPtr<ScreenshotTaker> screenshot_taker,
+ scoped_refptr<base::RefCountedBytes> png_data,
drive::DriveFileError error,
const base::FilePath& local_path) {
if (error != drive::DRIVE_FILE_OK) {
LOG(ERROR) << "Failed to write screenshot image to Google Drive: " << error;
+ PostShowNotification(
+ screenshot_taker,
+ ScreenshotTakerObserver::SCREENSHOT_CREATE_FILE_FAILED,
+ local_path);
return;
}
- SaveScreenshotInternal(local_path, png_data);
+ SaveScreenshotInternal(screenshot_taker, local_path, png_data);
}
void EnsureDirectoryExistsCallback(
+ base::WeakPtr<ScreenshotTaker> screenshot_taker,
Profile* profile,
const base::FilePath& screenshot_path,
scoped_refptr<base::RefCountedBytes> png_data,
@@ -91,39 +163,55 @@ void EnsureDirectoryExistsCallback(
// of the target file exists.
if (error == drive::DRIVE_FILE_OK ||
error == drive::DRIVE_FILE_ERROR_EXISTS) {
+ // Note: The last two arguments of SaveScreenshotToDrive are appended by
+ // PrepareWritableFileAndRun.
drive::util::PrepareWritableFileAndRun(
profile,
screenshot_path,
- base::Bind(&SaveScreenshotToDrive, png_data));
+ base::Bind(&SaveScreenshotToDrive, screenshot_taker, png_data));
} else {
LOG(ERROR) << "Failed to ensure the existence of the specified directory "
<< "in Google Drive: " << error;
+ ShowNotificationCaller(
+ screenshot_taker,
+ ScreenshotTakerObserver::SCREENSHOT_CHECK_DIR_FAILED,
+ screenshot_path);
}
}
-void PostSaveScreenshotTask(const base::FilePath& screenshot_path,
+void PostSaveScreenshotTask(base::WeakPtr<ScreenshotTaker> screenshot_taker,
+ Profile* profile,
+ const base::FilePath& screenshot_path,
scoped_refptr<base::RefCountedBytes> png_data) {
if (drive::util::IsUnderDriveMountPoint(screenshot_path)) {
- Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
- if (profile) {
- drive::util::EnsureDirectoryExists(
- profile,
- screenshot_path.DirName(),
- base::Bind(&EnsureDirectoryExistsCallback,
- profile,
- screenshot_path,
- png_data));
- }
+ // Note: The last argument of EnsureDirectoryExistsCallback is
+ // appended by EnsureDirectoryExists.
+ drive::util::EnsureDirectoryExists(
+ profile,
+ screenshot_path.DirName(),
+ base::Bind(&EnsureDirectoryExistsCallback,
+ screenshot_taker,
+ profile,
+ screenshot_path,
+ png_data));
} else {
content::BrowserThread::GetBlockingPool()->PostTask(
- FROM_HERE, base::Bind(&SaveScreenshot, screenshot_path, png_data));
+ FROM_HERE, base::Bind(&SaveScreenshot,
+ screenshot_taker,
+ screenshot_path,
+ png_data));
}
}
#else
-void PostSaveScreenshotTask(const base::FilePath& screenshot_path,
+void PostSaveScreenshotTask(base::WeakPtr<ScreenshotTaker> screenshot_taker,
+ Profile* profile,
+ const base::FilePath& screenshot_path,
scoped_refptr<base::RefCountedBytes> png_data) {
content::BrowserThread::GetBlockingPool()->PostTask(
- FROM_HERE, base::Bind(&SaveScreenshot, screenshot_path, png_data));
+ FROM_HERE, base::Bind(&SaveScreenshot,
+ screenshot_taker,
+ screenshot_path,
+ png_data));
}
#endif
@@ -148,7 +236,10 @@ bool GrabWindowSnapshot(aura::Window* window,
} // namespace
-ScreenshotTaker::ScreenshotTaker() {
+ScreenshotTaker::ScreenshotTaker(Profile* profile)
+ : profile_(profile),
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
+ DCHECK(profile_);
}
ScreenshotTaker::~ScreenshotTaker() {
@@ -156,11 +247,17 @@ ScreenshotTaker::~ScreenshotTaker() {
void ScreenshotTaker::HandleTakeScreenshotForAllRootWindows() {
base::FilePath screenshot_directory;
- if (!ScreenshotSource::GetScreenshotDirectory(&screenshot_directory))
+ if (!screenshot_directory_for_test_.empty()) {
+ screenshot_directory = screenshot_directory_for_test_;
+ } else if (!ScreenshotSource::GetScreenshotDirectory(&screenshot_directory)) {
+ ShowNotification(ScreenshotTakerObserver::SCREENSHOT_GET_DIR_FAILED,
+ base::FilePath());
return;
-
- std::string screenshot_basename =
+ }
+ std::string screenshot_basename = !screenshot_basename_for_test_.empty() ?
+ screenshot_basename_for_test_ :
ScreenshotSource::GetScreenshotBaseFilename();
+
ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
// Reorder root_windows to take the primary root window's snapshot at first.
aura::RootWindow* primary_root = ash::Shell::GetPrimaryRootWindow();
@@ -176,12 +273,16 @@ void ScreenshotTaker::HandleTakeScreenshotForAllRootWindows() {
gfx::Rect rect = root_window->bounds();
if (root_windows.size() > 1)
basename += base::StringPrintf(" - Display %d", static_cast<int>(i + 1));
+ base::FilePath screenshot_path =
+ screenshot_directory.AppendASCII(basename + ".png");
if (GrabWindowSnapshot(root_window, rect, &png_data->data())) {
- DisplayVisualFeedback(rect);
- PostSaveScreenshotTask(
- screenshot_directory.AppendASCII(basename + ".png"), png_data);
+ PostSaveScreenshotTask(factory_.GetWeakPtr(), profile_,
+ screenshot_path, png_data);
} else {
LOG(ERROR) << "Failed to grab the window screenshot for " << i;
+ ShowNotification(
+ ScreenshotTakerObserver::SCREENSHOT_GRABWINDOW_FULL_FAILED,
+ screenshot_path);
}
}
last_screenshot_timestamp_ = base::Time::Now();
@@ -192,20 +293,30 @@ void ScreenshotTaker::HandleTakePartialScreenshot(
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
base::FilePath screenshot_directory;
- if (!ScreenshotSource::GetScreenshotDirectory(&screenshot_directory))
+ if (!screenshot_directory_for_test_.empty()) {
+ screenshot_directory = screenshot_directory_for_test_;
+ } else if (!ScreenshotSource::GetScreenshotDirectory(&screenshot_directory)) {
+ ShowNotification(ScreenshotTakerObserver::SCREENSHOT_GET_DIR_FAILED,
+ base::FilePath());
return;
+ }
scoped_refptr<base::RefCountedBytes> png_data(new base::RefCountedBytes);
+ std::string screenshot_basename = !screenshot_basename_for_test_.empty() ?
+ screenshot_basename_for_test_ :
+ ScreenshotSource::GetScreenshotBaseFilename();
+ base::FilePath screenshot_path =
+ screenshot_directory.AppendASCII(screenshot_basename + ".png");
if (GrabWindowSnapshot(window, rect, &png_data->data())) {
last_screenshot_timestamp_ = base::Time::Now();
- DisplayVisualFeedback(rect);
- PostSaveScreenshotTask(
- screenshot_directory.AppendASCII(
- ScreenshotSource::GetScreenshotBaseFilename() + ".png"),
- png_data);
+ PostSaveScreenshotTask(factory_.GetWeakPtr(), profile_,
+ screenshot_path, png_data);
} else {
LOG(ERROR) << "Failed to grab the window screenshot";
+ ShowNotification(
+ ScreenshotTakerObserver::SCREENSHOT_GRABWINDOW_PARTIAL_FAILED,
+ screenshot_path);
}
}
@@ -216,25 +327,57 @@ bool ScreenshotTaker::CanTakeScreenshot() {
kScreenshotMinimumIntervalInMS);
}
-void ScreenshotTaker::CloseVisualFeedbackLayer() {
- visual_feedback_layer_.reset();
+void ScreenshotTaker::ShowNotification(
+ ScreenshotTakerObserver::Result screenshot_result,
+ const base::FilePath& screenshot_path) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ static int id = 0;
+ std::string id_text = base::StringPrintf("screenshot_%3.3d", ++id);
+ string16 replace_id = UTF8ToUTF16(id_text);
+ bool success =
+ (screenshot_result == ScreenshotTakerObserver::SCREENSHOT_SUCCESS);
+ Notification notification(
+ GURL(kNotificationOriginUrl),
+ ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+ IDR_SCREENSHOT_NOTIFICATION_ICON),
+ l10n_util::GetStringUTF16(
+ success ?
+ IDS_ASH_SCREENSHOT_NOTIFICATION_TITLE_SUCCESS :
+ IDS_ASH_SCREENSHOT_NOTIFICATION_TITLE_FAIL),
+ l10n_util::GetStringUTF16(
+ success ?
+ IDS_ASH_SCREENSHOT_NOTIFICATION_TEXT_SUCCESS :
+ IDS_ASH_SCREENSHOT_NOTIFICATION_TEXT_FAIL),
+ WebKit::WebTextDirectionDefault,
+ string16(),
+ replace_id,
+ new ScreenshotTakerNotificationDelegate(id_text,
+ success,
+ screenshot_path));
+ g_browser_process->notification_ui_manager()->Add(notification, profile_);
+
+ FOR_EACH_OBSERVER(ScreenshotTakerObserver, observers_,
+ OnScreenshotCompleted(screenshot_result, screenshot_path));
+}
+
+void ScreenshotTaker::AddObserver(ScreenshotTakerObserver* observer) {
+ observers_.AddObserver(observer);
}
-void ScreenshotTaker::DisplayVisualFeedback(const gfx::Rect& rect) {
- visual_feedback_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
- visual_feedback_layer_->SetColor(SK_ColorWHITE);
- visual_feedback_layer_->SetOpacity(kVisualFeedbackLayerOpacity);
- visual_feedback_layer_->SetBounds(rect);
+void ScreenshotTaker::RemoveObserver(ScreenshotTakerObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
- ui::Layer* parent = ash::Shell::GetContainer(
- ash::Shell::GetActiveRootWindow(),
- ash::internal::kShellWindowId_OverlayContainer)->layer();
- parent->Add(visual_feedback_layer_.get());
- visual_feedback_layer_->SetVisible(true);
+bool ScreenshotTaker::HasObserver(ScreenshotTakerObserver* observer) const {
+ return observers_.HasObserver(observer);
+}
+
+void ScreenshotTaker::SetScreenshotDirectoryForTest(
+ const base::FilePath& directory) {
+ screenshot_directory_for_test_ = directory;
+}
- MessageLoopForUI::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ScreenshotTaker::CloseVisualFeedbackLayer,
- base::Unretained(this)),
- base::TimeDelta::FromMilliseconds(kVisualFeedbackLayerDisplayTimeMs));
+void ScreenshotTaker::SetScreenshotBasenameForTest(
+ const std::string& basename){
+ screenshot_basename_for_test_ = basename;
}

Powered by Google App Engine
This is Rietveld 408576698