diff options
21 files changed, 799 insertions, 121 deletions
diff --git a/app/x11_util.cc b/app/x11_util.cc index edf5f2f..78e09fc 100644 --- a/app/x11_util.cc +++ b/app/x11_util.cc @@ -736,7 +736,7 @@ void GrabWindowSnapshot(GtkWindow* gtk_window, Display* display = GDK_WINDOW_XDISPLAY(gdk_window); XID win = GDK_WINDOW_XID(gdk_window); XWindowAttributes attr; - if (XGetWindowAttributes(display, win, &attr) != 0) { + if (XGetWindowAttributes(display, win, &attr) == 0) { LOG(ERROR) << "Couldn't get window attributes"; return; } diff --git a/base/mac_util.h b/base/mac_util.h index 2c59a87..bfe2079 100644 --- a/base/mac_util.h +++ b/base/mac_util.h @@ -118,7 +118,8 @@ void ActivateProcess(pid_t); // Pulls a snapshot of the entire browser into png_representation. void GrabWindowSnapshot(NSWindow* window, - std::vector<unsigned char>* png_representation); + std::vector<unsigned char>* png_representation, + int* width, int* height); // Takes a path to an (executable) binary and tries to provide the path to an // application bundle containing it. It takes the outermost bundle that it can diff --git a/base/mac_util.mm b/base/mac_util.mm index 00ef9e09..cd7a949 100644 --- a/base/mac_util.mm +++ b/base/mac_util.mm @@ -244,7 +244,8 @@ bool ShouldWindowsMiniaturizeOnDoubleClick() { } void GrabWindowSnapshot(NSWindow* window, - std::vector<unsigned char>* png_representation) { + std::vector<unsigned char>* png_representation, + int* width, int* height) { // Make sure to grab the "window frame" view so we get current tab + // tabstrip. NSView* view = [[window contentView] superview]; @@ -255,6 +256,8 @@ void GrabWindowSnapshot(NSWindow* window, const unsigned char* buf = static_cast<const unsigned char*>([data bytes]); NSUInteger length = [data length]; if (buf != NULL && length > 0){ + *width = static_cast<int>([rep pixelsWide]); + *height = static_cast<int>([rep pixelsHigh]); png_representation->assign(buf, buf + length); DCHECK(png_representation->size() > 0); } diff --git a/base/mac_util_unittest.mm b/base/mac_util_unittest.mm index b77472b..aebb731 100644 --- a/base/mac_util_unittest.mm +++ b/base/mac_util_unittest.mm @@ -66,7 +66,9 @@ TEST_F(MacUtilTest, TestGrabWindowSnapshot) { scoped_ptr<std::vector<unsigned char> > png_representation( new std::vector<unsigned char>); - GrabWindowSnapshot(window, png_representation.get()); + int width, height; + GrabWindowSnapshot(window, png_representation.get(), + &width, &height); // Copy png back into NSData object so we can make sure we grabbed a png. scoped_nsobject<NSData> image_data( diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index a465f19..7430470 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4102,6 +4102,23 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_BUGREPORT_DESCRIPTION_LABEL" desc="Label for description field"> Description: </message> + <if expr="pp_ifdef('chromeos')"> + <message name="IDS_BUGREPORT_INCLUDE_LAST_SCREEN_IMAGE" desc="Radio button for including the last screen image on the bug report dialog box"> + Send last screen shot + </message> + <message name="IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE" desc="Radio button for including a new screen image on the bug report dialog box"> + Send a new screen shot + </message> + <message name="IDS_BUGREPORT_INCLUDE_SYSTEM_INFORMATION_CHKBOX" desc="Checkbox for including system information on the bug report dialog box"> + Send system information + </message> + <message name="IDS_BUGREPORT_SYSTEM_INFORMATION_URL" desc="URL for system information on the bug report dialog box"> + file:///etc/logs/last + </message> + <message name="IDS_BUGREPORT_SYSTEM_INFORMATION_URL_TEXT" desc="Text for system information url on the bug report dialog box"> + System Information + </message> + </if> <message name="IDS_BUGREPORT_INCLUDE_PAGE_SOURCE_CHKBOX" desc="Checkbox for including page source"> Send source of current page </message> diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index f375ce0..492ebfb 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -1609,10 +1609,15 @@ void Browser::OpenNewProfileDialog() { } void Browser::OpenBugReportDialog() { +#if defined(OS_CHROMEOS) + UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_); + window_->ShowReportBugDialog(); +#else TabContents* contents = GetSelectedTabContents(); if (!contents) return; ShowBrokenPageTab(contents); +#endif } void Browser::ToggleBookmarkBar() { diff --git a/chrome/browser/bug_report_util.cc b/chrome/browser/bug_report_util.cc index b23943e..37aa8f8 100644 --- a/chrome/browser/bug_report_util.cc +++ b/chrome/browser/bug_report_util.cc @@ -17,6 +17,8 @@ #include "grit/locale_settings.h" #include "unicode/locid.h" +#include <string> + namespace { const int kBugReportVersion = 1; @@ -26,7 +28,17 @@ const char kReportPhishingUrl[] = // URL to post bug reports to. const char* const kBugReportPostUrl = - "http://web-bug.appspot.com/bugreport"; + "http://feedback2-dev.corp.google.com/tools/feedback/chrome/__submit"; + +const char* const kProtBufMimeType = "application/x-protobuf"; +const char* const kPngMimeType = "image/png"; + +// Tags we use in product specific data +const char* const kPageTitleTag = "PAGE TITLE"; +const char* const kProblemTypeTag = "PROBLEM TYPE"; +const char* const kChromeVersionTag = "CHROME VERSION"; +const char* const kOsVersionTag = "OS VERSION"; + } // namespace @@ -89,60 +101,59 @@ void BugReportUtil::SetOSVersion(std::string *os_version) { #endif } -// Create a MIME boundary marker (27 '-' characters followed by 16 hex digits). -void BugReportUtil::CreateMimeBoundary(std::string *out) { - int r1 = rand(); - int r2 = rand(); - SStringPrintf(out, "---------------------------%08X%08X", r1, r2); +// static +void BugReportUtil::AddFeedbackData( + userfeedback::ExternalExtensionSubmit* feedback_data, + const std::string& key, const std::string& value) { + // Create log_value object and add it to the web_data object + userfeedback::ProductSpecificData log_value; + log_value.set_key(key); + log_value.set_value(value); + userfeedback::WebData* web_data = feedback_data->mutable_web_data(); + *(web_data->add_product_specific_data()) = log_value; } // static void BugReportUtil::SendReport(Profile* profile, - std::string page_title_text, + const std::string& page_title_text, int problem_type, - std::string page_url_text, - std::string description, + const std::string& page_url_text, + const std::string& description, const char* png_data, - int png_data_length) { + int png_data_length, + int png_width, + int png_height) { GURL post_url(kBugReportPostUrl); - std::string mime_boundary; - CreateMimeBoundary(&mime_boundary); - // Create a request body and add the mandatory parameters. - std::string post_body; + // Create google feedback protocol buffer objects + userfeedback::ExternalExtensionSubmit feedback_data; + // type id set to 0, unused field but needs to be initialized to 0 + feedback_data.set_type_id(0); + + userfeedback::CommonData* common_data = feedback_data.mutable_common_data(); + userfeedback::WebData* web_data = feedback_data.mutable_web_data(); - // Add the protocol version: - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append("Content-Disposition: form-data; " - "name=\"data_version\"\r\n\r\n"); - post_body.append(StringPrintf("%d\r\n", kBugReportVersion)); + // set GAIA id to 0 to indicate no username available + common_data->set_gaia_id(0); // Add the page title. - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append(page_title_text + "\r\n"); - - // Add the problem type. - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append("Content-Disposition: form-data; " - "name=\"problem\"\r\n\r\n"); - post_body.append(StringPrintf("%d\r\n", problem_type)); - - // Add in the URL, if we have one. - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append("Content-Disposition: form-data; " - "name=\"url\"\r\n\r\n"); - - // Convert URL to UTF8. - if (page_url_text.empty()) - post_body.append("n/a\r\n"); - else - post_body.append(page_url_text + "\r\n"); - - // Add Chrome version. - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append("Content-Disposition: form-data; " - "name=\"chrome_version\"\r\n\r\n"); + AddFeedbackData(&feedback_data, std::string(kPageTitleTag), + page_title_text); + AddFeedbackData(&feedback_data, std::string(kProblemTypeTag), + StringPrintf("%d\r\n", problem_type)); + + // Add the description to the feedback object + common_data->set_description(description); + + // Add the language + std::string chrome_locale = g_browser_process->GetApplicationLocale(); + common_data->set_source_descripton_language(chrome_locale); + + // Set the url + web_data->set_url(page_url_text); + + // Add the Chrome version std::string chrome_version; scoped_ptr<FileVersionInfo> version_info( chrome_app::GetChromeVersionInfo()); @@ -152,79 +163,45 @@ void BugReportUtil::SendReport(Profile* profile, " (" + WideToUTF8(version_info->last_change()) + ")"; } - if (chrome_version.empty()) - post_body.append("n/a\r\n"); - else - post_body.append(chrome_version + "\r\n"); + if (!chrome_version.empty()) + AddFeedbackData(&feedback_data, std::string(kChromeVersionTag), + chrome_version); // Add OS version (eg, for WinXP SP2: "5.1.2600 Service Pack 2"). std::string os_version = ""; - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append("Content-Disposition: form-data; " - "name=\"os_version\"\r\n\r\n"); SetOSVersion(&os_version); - post_body.append(os_version + "\r\n"); + AddFeedbackData(&feedback_data, std::string(kOsVersionTag), os_version); - // Add locale. -#if defined(OS_MACOSX) - std::string chrome_locale = g_browser_process->GetApplicationLocale(); -#else - icu::Locale locale = icu::Locale::getDefault(); - const char *lang = locale.getLanguage(); - std::string chrome_locale = (lang)? lang:"en"; -#endif - - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append("Content-Disposition: form-data; " - "name=\"chrome_locale\"\r\n\r\n"); - post_body.append(chrome_locale + "\r\n"); - - // Add a description if we have one. - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append("Content-Disposition: form-data; " - "name=\"description\"\r\n\r\n"); - - if (description.empty()) - post_body.append("n/a\r\n"); - else - post_body.append(description + "\r\n"); // Include the page image if we have one. - if (png_data != NULL && png_data_length > 0) { - post_body.append("--" + mime_boundary + "\r\n"); - post_body.append("Content-Disposition: form-data; name=\"screenshot\"; " - "filename=\"screenshot.png\"\r\n"); - post_body.append("Content-Type: application/octet-stream\r\n"); - post_body.append(StringPrintf("Content-Length: %d\r\n\r\n", - png_data_length)); - post_body.append(png_data, png_data_length); - post_body.append("\r\n"); + if (png_data) { + userfeedback::PostedScreenshot screenshot; + screenshot.set_mime_type(kPngMimeType); + + // Set the dimensions of the screenshot + userfeedback::Dimensions dimensions; + dimensions.set_width(static_cast<float>(png_width)); + dimensions.set_height(static_cast<float>(png_height)); + *(screenshot.mutable_dimensions()) = dimensions; + screenshot.set_binary_content(std::string(png_data, png_data_length)); + + // Set the screenshot object in feedback + *(feedback_data.mutable_screenshot()) = screenshot; } // TODO(awalker): include the page source if we can get it. // if (include_page_source_checkbox_->checked()) { // } - // Terminate the body. - post_body.append("--" + mime_boundary + "--\r\n"); - // We have the body of our POST, so send it off to the server. URLFetcher* fetcher = new URLFetcher(post_url, URLFetcher::POST, new BugReportUtil::PostCleanup); fetcher->set_request_context(profile->GetRequestContext()); - std::string mime_type("multipart/form-data; boundary="); - mime_type += mime_boundary; - fetcher->set_upload_data(mime_type, post_body); - fetcher->Start(); -} -// static -std::string BugReportUtil::GetMimeType() { - std::string mime_type("multipart/form-data; boundary="); - std::string mime_boundary; - CreateMimeBoundary(&mime_boundary); - mime_type += mime_boundary; - return mime_type; + std::string post_body; + feedback_data.SerializeToString(&post_body); + fetcher->set_upload_data(std::string(kProtBufMimeType), post_body); + fetcher->Start(); } // static @@ -236,4 +213,3 @@ void BugReportUtil::ReportPhishing(TabContents* currentTab, GURL(), PageTransition::LINK); } - diff --git a/chrome/browser/bug_report_util.h b/chrome/browser/bug_report_util.h index aef1760..a56d4e1 100644 --- a/chrome/browser/bug_report_util.h +++ b/chrome/browser/bug_report_util.h @@ -15,6 +15,11 @@ #endif #include "base/scoped_ptr.h" +#include "chrome/browser/userfeedback/proto/common.pb.h" +#include "chrome/browser/userfeedback/proto/extension.pb.h" +#include "chrome/browser/userfeedback/proto/math.pb.h" +#include "gfx/rect.h" + class Profile; class TabContents; @@ -44,26 +49,28 @@ class BugReportUtil { // Generates bug report data. static void SendReport(Profile* profile, - std::string page_title_text, + const std::string& page_title_text, int problem_type, - std::string page_url_text, - std::string description, + const std::string& page_url_text, + const std::string& description, const char* png_data, - int png_data_length); + int png_data_length, + int png_width, + int png_height); // Redirects the user to Google's phishing reporting page. static void ReportPhishing(TabContents* currentTab, const std::string& phishing_url); - static std::string GetMimeType(); - class PostCleanup; private: - static void CreateMimeBoundary(std::string *out); + // Add a key value pair to the feedback object + static void AddFeedbackData( + userfeedback::ExternalExtensionSubmit* feedback_data, + const std::string& key, const std::string& value); DISALLOW_IMPLICIT_CONSTRUCTORS(BugReportUtil); }; #endif // CHROME_BROWSER_BUG_REPORT_UTIL_H_ - diff --git a/chrome/browser/cocoa/bug_report_window_controller.h b/chrome/browser/cocoa/bug_report_window_controller.h index 6c79080..88a7ca6 100644 --- a/chrome/browser/cocoa/bug_report_window_controller.h +++ b/chrome/browser/cocoa/bug_report_window_controller.h @@ -25,6 +25,9 @@ class TabContents; // Holds screenshot of current tab. std::vector<unsigned char> pngData_; + // Width and height of the current tab's screenshot. + int pngWidth_; + int pngHeight_; // Values bound to data in the dialog box. These values cannot be boxed in // scoped_nsobjects because we use them for bindings. diff --git a/chrome/browser/cocoa/bug_report_window_controller.mm b/chrome/browser/cocoa/bug_report_window_controller.mm index 650f8b3..df29f99 100644 --- a/chrome/browser/cocoa/bug_report_window_controller.mm +++ b/chrome/browser/cocoa/bug_report_window_controller.mm @@ -63,13 +63,17 @@ currentTab_->controller().GetActiveEntry()->url().spec())]; [self setPageTitle:base::SysUTF16ToNSString(currentTab_->GetTitle())]; mac_util::GrabWindowSnapshot( - currentTab_->view()->GetTopLevelNativeWindow(), &pngData_); + currentTab_->view()->GetTopLevelNativeWindow(), &pngData_, + &pngWidth_, &pngHeight_); } else { // If no current tab exists, create a menu without the "broken page" // options, with page URL and title empty, and screenshot disabled. [self setSendScreenshot:NO]; [self setDisableScreenshotCheckbox:YES]; } + + pngHeight_ = 0; + pngWidth_ = 0; } return self; } @@ -112,7 +116,7 @@ base::SysNSStringToUTF8(bugDescription_), sendScreenshot_ && !pngData_.empty() ? reinterpret_cast<const char *>(&(pngData_[0])) : NULL, - pngData_.size()); + pngData_.size(), pngWidth_, pngHeight_); } [self closeDialog]; } diff --git a/chrome/browser/userfeedback/proto/annotations.proto b/chrome/browser/userfeedback/proto/annotations.proto new file mode 100644 index 0000000..b99aa04 --- /dev/null +++ b/chrome/browser/userfeedback/proto/annotations.proto @@ -0,0 +1,26 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// Author: micapolos@google.com (Michal Pociecha-Los) +// +// Messages containing data about the annotations drawn on the screenshot of a +// web page. + +syntax = "proto2"; + +package userfeedback; + +import "math.proto"; +import "dom.proto"; + +// An annotation drawn by the user on the screenshot of a web page. +message Annotation { + // A rectangular area covered by this annotation on annotated image. + // The (0, 0) coordinate is placed in the top-left corner of the image. + // One unit corresponds to one pixel. + required Rectangle rectangle = 1; + + // A snippet of text displayed inside annotated portion of a web page. + optional string snippet = 2; + + // A path from root element of the document to the annotated element. + optional HtmlPath annotatedElementPath = 3; +}; diff --git a/chrome/browser/userfeedback/proto/common.proto b/chrome/browser/userfeedback/proto/common.proto new file mode 100644 index 0000000..97c60fb --- /dev/null +++ b/chrome/browser/userfeedback/proto/common.proto @@ -0,0 +1,22 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// Author: morgwai@google.com (Morgwai Kotarbinski) +// +// Basic messages used by all systems (extension, feedbackserver, +// silver-bullet clustering, android etc). + +syntax = "proto2"; + +package userfeedback; + +// Data present in all kinds of feedbacks, regardless of source (Web, Android, +// other). +message CommonData { + optional fixed64 gaia_id = 1; + + // Description of the problem entered by user. + optional string description = 2; + optional string description_translated = 4; + optional string source_descripton_language = 5 [ default = "en" ]; + + optional string user_email = 3; +}; diff --git a/chrome/browser/userfeedback/proto/config.proto b/chrome/browser/userfeedback/proto/config.proto new file mode 100644 index 0000000..f36c482 --- /dev/null +++ b/chrome/browser/userfeedback/proto/config.proto @@ -0,0 +1,139 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// Author: morgwai@google.com (Morgwai Kotarbinski) +// +// Messages containing configuration of Feedback Service +// that control classification and processing of submitted feedbacks. + +syntax = "proto2"; + +package userfeedback; + +// Product for which feedback can be sent: GMail, Writely etc. +message Product { + required int32 id = 1; + + required string name = 2; + + repeated string owner = 3; +}; + +// Contains information needed to check whether particular +// feedback type applies to the page user is browsing and forward +// it's execution to a specific handler. It also carries information +// about the creator. +// TODO(morgwai): design new structure of Type with fields relevant +// for android, web, selenium grouped into submessages. +message FeedbackTypeData { + // index of feedback type as found in database + required int32 id = 1; + + // Specifies whether this feedback type is currently enabled and + // feedback of this type can be submitted. + required bool enabled = 2; + + // Problem name of this feedback type on Google Feedback pages. + required string problem_name = 3; + + // Name of the product to which this feedback type belongs. + optional string product_name = 4; + + // Tag 5 is used by some legacy data that is already in production db. + + // matcher to execute against page + required MatcherData matcher = 6; + + // Comma separated list of email addresses to which email notification + // is sent upon each new feedback of this type. + // No email is sent if this field is set to an empty string. + required string notification_email = 7; + + // Do not use tag 8, 9, 10. They were used by a legacy field. + + // Encapsulates different kind of feedback type. + enum Kind { + // Product feedback type. + PRODUCT = 1; + // Special feedback type (e.g. fixit). + SPECIAL = 2; + } + + // Kind of feedback type. + optional Kind kind = 11 [default=PRODUCT]; + + // Prefix to be added to summary of notification email sent for feedback of this + // type. + optional string summary_prefix = 12; + + // String template with which "Additional Info" field in extension + // should be initially filled. + optional string template = 13; + + // ID of the product this feedback type belongs to. + optional int32 product_id = 14; + + // Tag that is used for marking feedback types that require non-ordinary handling. + // E.g: This field is equal: + // "unclassified" for Unclassified feedback, + // "android" for android feedback + // "selenium" for selenium feedback + optional string tag = 15; + + // Problem description visible in feedback extension. + optional string problem_description = 16; + + // Visibilities of feedback type. + enum Visibility { + // feedback type visible in external extension only + EXTERNAL = 1; + // feedback type visible in internal extension only + INTERNAL = 2; + } + + // Specifies the visibility of this feedback type. + optional Visibility visibility = 17 [default=INTERNAL]; + + // tag 18 was used by removed field + + // Specifies Buganizer fields + // TODO(kaczmarek): enable once we migrated to new protos. + // optional BuganizerSettings buganizer_settings = 19; + + // Channel via which notification about feedback should be send + enum NotifyChannel { + // Send email notification. + EMAIL = 1; + // File a bug in buganizer. + BUGANIZER = 2; + // File a bug in issue tracker. + ISSUE_TRACKER = 3; + } + + // Specifies channel via which notification about feedback of this type should be sent. + optional NotifyChannel notify_channel = 20 [default=EMAIL]; + + // Granularity of notifications. + enum NotificationGranularity { + // Send notification per each feedback. + FEEDBACK = 1; + // Send notification per clustered group of similar feedbacks. + CLUSTER = 2; + } + + // Specifies granularity of notifications send for feedbacks of this type. + optional NotificationGranularity notification_granularity = 21 [default=FEEDBACK]; + + // Threshold for number of feedbacks in a cluster at which notification is sent. + optional int32 clustering_threshold = 22 [default=5]; +}; + +// Used to detect content relevant to particular type of feedback. +message MatcherData { + // XPATH expression to match against page. + required string content_matcher = 1; + + // Regexp matching page URL. + required string url_matcher = 2; + + // Approval by feedback admins + optional bool url_matcher_approved = 3 [default=true]; +}; diff --git a/chrome/browser/userfeedback/proto/dom.proto b/chrome/browser/userfeedback/proto/dom.proto new file mode 100644 index 0000000..23958ac --- /dev/null +++ b/chrome/browser/userfeedback/proto/dom.proto @@ -0,0 +1,98 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// Author: micapolos@google.com (Michal Pociecha-Los) +// +// Messages containing DOM data captured from the browser. +// It includes the structure of the HTML document and Navigator data. + +syntax = "proto2"; + +package userfeedback; + +// Data captured from HTMLDocument DOM object. +message HtmlDocument { + + // The value of document.URL property. + required string url = 1; + + // The value of document.title property. + optional string title = 2; + + // The value of document.documentElement property. + optional HtmlElement document_element = 3; +}; + +// Data captured from HTMLElement DOM object. +message HtmlElement { + + // The value of element.tagName property. + required string tag_name = 1; + + // The value of element.id property. + optional string id = 2; + + // The value of element.className property. + optional string class_name = 3; + + // A list of child elements. + repeated HtmlElement child_element = 4; + + // The value of frame.contentDocument property for FRAME and IFRAME elements. + optional HtmlDocument frame_content_document = 5; +}; + +// Data captured from DOM Navigator object. +message Navigator { + + // The value of 'navigator.appCodeName' property. + optional string app_code_name = 1; + + // The value of 'navigator.appName' property. + optional string app_name = 2; + + // The value of 'navigator.appVersion' property. + optional string app_version = 3; + + // The value of 'navigator.appMinorVersion' property. + optional string app_minor_version = 4; + + // The value of 'navigator.cookieEnabled' property. + optional bool cookie_enabled = 5; + + // The value of 'navigator.cpuClass' property. + optional string cpu_class = 6; + + // The value of 'navigator.onLine' property. + optional bool on_line = 7; + + // The value of 'navigator.platform' property. + optional string platform = 8; + + // The value of 'navigator.browserLanguage' property. + optional string browser_language = 9; + + // The value of 'navigator.systemLanguage' property. + optional string system_language = 10; + + // The value of 'navigator.userAgent' property. + optional string user_agent = 11; + + // The return value of 'navigator.javaEnabled()' method. + optional bool java_enabled = 12; + + // The return value of 'navigator.taintEnabled()' method. + optional bool taint_enabled = 13; + + // Plugin names specified by 'navigator.plugins' property. + repeated string plugin_name = 14; +}; + +// A path in the HTML document between two elements, which are in the +// ancestor-descendant relationship. +message HtmlPath { + + // Ordered list of zero-based indices. + // Empty path selects root element. + // Non-negative index N selects (N+1)-th child. + // Index -1 selects root element from frame content document. + repeated int32 index = 1; +}; diff --git a/chrome/browser/userfeedback/proto/extension.proto b/chrome/browser/userfeedback/proto/extension.proto new file mode 100644 index 0000000..d600f8a --- /dev/null +++ b/chrome/browser/userfeedback/proto/extension.proto @@ -0,0 +1,99 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// Author: morgwai@google.com (Morgwai Kotarbinski) +// +// Messages sent from extension to feedback server as JSON. + +syntax = "proto2"; + +package userfeedback; + +import "common.proto"; +import "dom.proto"; +import "math.proto"; +import "web.proto"; + +// Sent along with request for extension page when user attempts to open +// feedback tab. +message ExtensionPageRequestParams { + + required ExtensionDetails extension_details = 1; + + // Url of the page (without request params) that user wants to open + // feedback tool for. + required string url = 2; +}; + +message PostedScreenshot { + + required string mime_type = 1; + + required Dimensions dimensions = 2; + + optional string base64_content = 3; + + optional bytes binary_content = 4; +}; + +// Contains data about possible errors on the client side. +// Describes number of attempts to send feedback and possible error codes/ +// exceptions which occured. +message ExtensionErrors { + + required int32 number_of_attempts = 1; + + required string errors = 2; +}; + +// Sent when user hits final submit button in external extension. +// NOTE: Field numbers for ExternalExtensionSubmit and InternalExtensionSubmit +// share the same number space, because we don't want submission from internal +// extension to the external address, or submission from external extension to +// internal address, work by accident, partially work, or break in an odd way. +// If the field numbers were overlapping for both protos, such cross-submission +// might work, due to the specifics of JsPbLite. +message ExternalExtensionSubmit { + + required CommonData common_data = 1; + + required WebData web_data = 2; + + required int32 type_id = 3; + + optional PostedScreenshot screenshot = 4; + + optional HtmlDocument html_document_structure = 5; + + optional ExtensionErrors extension_errors = 13; +}; + +// Sent when user hits final submit button in internal extension. +// NOTE: Field numbers for ExternalExtensionSubmit and InternalExtensionSubmit +// share the same number space. See comment for ExternalExtensionSubmit. +message InternalExtensionSubmit { + + required CommonData common_data = 6; + + required WebData web_data = 7; + + optional int32 type_id = 8; + + optional PostedScreenshot screenshot = 9; + + optional HtmlDocument html_document_structure = 10; + + optional InternalWebData internal_data = 11; + + optional ExtensionErrors extension_errors = 12; +}; + +// A query for suggestions, sent when the user hits the preview button. +message SuggestQuery { + + required CommonData common_data = 1; + + required WebData web_data = 2; + + required int32 type_id = 3; + + optional HtmlDocument html_document_structure = 4; +}; diff --git a/chrome/browser/userfeedback/proto/math.proto b/chrome/browser/userfeedback/proto/math.proto new file mode 100644 index 0000000..c189967 --- /dev/null +++ b/chrome/browser/userfeedback/proto/math.proto @@ -0,0 +1,22 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// Author: micapolos@google.com (Michal Pociecha-Los) +// +// Messages containing common math data structures. + +syntax = "proto2"; + +package userfeedback; + +// 2D Dimensions. +message Dimensions { + required float width = 1; + required float height = 2; +}; + +// Axis-aligned rectangle in 2D space. +message Rectangle { + required float left = 1; + required float top = 2; + required float width = 3; + required float height = 4; +}; diff --git a/chrome/browser/userfeedback/proto/web.proto b/chrome/browser/userfeedback/proto/web.proto new file mode 100644 index 0000000..fb9f6af --- /dev/null +++ b/chrome/browser/userfeedback/proto/web.proto @@ -0,0 +1,70 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// Author: jaceks@google.com (Jacek Surazski) + +syntax = "proto2"; + +package userfeedback; + +// Data present in Web related feedbacks + +import "annotations.proto"; +import "config.proto"; +import "dom.proto"; +import "math.proto"; + +// Data present in feedbacks sent from web extension. +message WebData { + // Data captured from DOM Navigator object. + optional Navigator navigator = 1; + + // Details of the extension from which this data was sent. + optional ExtensionDetails extension_details = 2; + + // The URL of the document. + // Useful when user opts out from sending html structure. + optional string url = 3; + + // A list of annotations. + repeated Annotation annotation = 4; + + // The ID of the suggestion selected by the user. + // Possible values: + // - Not set if no suggestions were shown, either because the version of + // the client did not support suggestions, suggestions were disabled or + // no matching suggestions were found. + // - NONE_OF_THE_ABOVE if the user has chosen "None of the above". + // - Empty string if suggestions were shown but the user hasn't chosen + // any of them (and also she hasn't chosen "None of the above"). + // - Actual suggestion identifier as returned from the server. + optional string suggestion_id = 5; + + repeated ProductSpecificData product_specific_data = 6; +}; + +message ExtensionDetails { + // Indicates browser and mpm release. + required string extension_version = 1; + + required string protocol_version = 2; +}; + +// Additional data sent by the internal version. +message InternalWebData { + // List of user names in google.com domain to which feedback should be sent + // directly apart from submitting it to server. + repeated string email_receiver = 1; + + // Subject of the problem entered by user. + optional string subject = 2; + + // If this flag is set then product support team should be notified + // immediately. + optional bool DEPRECATED_urgent = 3 [default = false]; +}; + +// Product specific data. Contains one key/value pair that is specific to the +// product for which feedback is submitted. +message ProductSpecificData { + required string key = 1; + optional string value = 2; +}; diff --git a/chrome/browser/views/bug_report_view.cc b/chrome/browser/views/bug_report_view.cc index 4903c75..2ae2f67 100644 --- a/chrome/browser/views/bug_report_view.cc +++ b/chrome/browser/views/bug_report_view.cc @@ -12,6 +12,7 @@ #include "chrome/browser/bug_report_util.h" #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" +#include "chrome/browser/browser_list.h" #include "chrome/browser/safe_browsing/safe_browsing_util.h" #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/navigation_entry.h" @@ -42,6 +43,8 @@ using views::GridLayout; // Report a bug data version. static const int kBugReportVersion = 1; +static const int kScreenImageRadioGroup = 2; + // Number of lines description field can display at one time. static const int kDescriptionLines = 5; @@ -105,9 +108,14 @@ void ShowBugReportView(views::Window* parent, win_util::GrabWindowSnapshot(parent->GetNativeWindow(), screenshot_png); #endif + // Get the size of the parent window to capture screenshot dimensions + gfx::Rect screenshot_size = parent->GetBounds(); + + // The BugReportView takes ownership of the png data, and will dispose of // it in its destructor. view->set_png_data(screenshot_png); + view->set_screenshot_size(screenshot_size); // Create and show the dialog. views::Window::CreateChromeWindow(parent->GetNativeWindow(), gfx::Rect(), @@ -184,6 +192,25 @@ void BugReportView::SetupControl() { l10n_util::GetString(IDS_BUGREPORT_INCLUDE_PAGE_SOURCE_CHKBOX)); include_page_source_checkbox_->SetChecked(true); +#if defined(OS_CHROMEOS) + include_last_screen_image_radio_ = new views::RadioButton( + l10n_util::GetString(IDS_BUGREPORT_INCLUDE_LAST_SCREEN_IMAGE), + kScreenImageRadioGroup); + last_screenshot_iv_ = new views::ImageView(); + + include_new_screen_image_radio_ = new views::RadioButton( + l10n_util::GetString(IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE), + kScreenImageRadioGroup); + + include_system_information_checkbox_ = new views::Checkbox( + l10n_util::GetString(IDS_BUGREPORT_INCLUDE_SYSTEM_INFORMATION_CHKBOX)); + system_information_url_ = new views::Link( + l10n_util::GetString(IDS_BUGREPORT_SYSTEM_INFORMATION_URL_TEXT)); + system_information_url_->SetController(this); + + include_last_screen_image_radio_->SetChecked(true); + include_system_information_checkbox_->SetChecked(true); +#endif include_page_image_checkbox_ = new views::Checkbox( l10n_util::GetString(IDS_BUGREPORT_INCLUDE_PAGE_IMAGE_CHKBOX)); include_page_image_checkbox_->SetChecked(true); @@ -232,11 +259,31 @@ void BugReportView::SetupControl() { // layout->SkipColumns(1); // layout->AddView(include_page_source_checkbox_); // layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + layout->StartRow(0, column_set_id); + layout->SkipColumns(1); +#if defined(OS_CHROMEOS) + // Radio boxes to select last screen shot or, + layout->AddView(include_last_screen_image_radio_); + layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + // new screenshot + layout->StartRow(0, column_set_id); + layout->SkipColumns(1); + layout->AddView(include_new_screen_image_radio_); + layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); + + // Checkbox for system information + layout->StartRow(0, column_set_id); + layout->SkipColumns(1); + layout->AddView(include_system_information_checkbox_); + + // TODO(rkc): Add a link once we're pulling system info, to it +#else if (include_page_image_checkbox_) { layout->StartRow(0, column_set_id); layout->SkipColumns(1); layout->AddView(include_page_image_checkbox_); } +#endif layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); } @@ -247,6 +294,30 @@ gfx::Size BugReportView::GetPreferredSize() { IDS_BUGREPORT_DIALOG_HEIGHT_LINES)); } + +void BugReportView::UpdateReportingControls(bool is_phishing_report) { + // page source, screen/page images, system information + // are not needed if it's a phishing report + + include_page_source_checkbox_->SetEnabled(!is_phishing_report); + include_page_source_checkbox_->SetChecked(!is_phishing_report); + +#if defined(OS_CHROMEOS) + include_last_screen_image_radio_->SetEnabled(!is_phishing_report); + include_new_screen_image_radio_->SetEnabled(!is_phishing_report); + + include_system_information_checkbox_->SetEnabled(!is_phishing_report); + include_system_information_checkbox_->SetChecked(!is_phishing_report); + + system_information_url_->SetEnabled(!is_phishing_report); +#else + if (include_page_image_checkbox_) { + include_page_image_checkbox_->SetEnabled(!is_phishing_report); + include_page_image_checkbox_->SetChecked(!is_phishing_report); + } +#endif +} + void BugReportView::ItemChanged(views::Combobox* combobox, int prev_index, int new_index) { @@ -265,12 +336,8 @@ void BugReportView::ItemChanged(views::Combobox* combobox, description_text_->SetText(WideToUTF16Hack(old_report_text_)); old_report_text_.clear(); } - include_page_source_checkbox_->SetEnabled(!is_phishing_report); - include_page_source_checkbox_->SetChecked(!is_phishing_report); - if (include_page_image_checkbox_) { - include_page_image_checkbox_->SetEnabled(!is_phishing_report); - include_page_image_checkbox_->SetChecked(!is_phishing_report); - } + + UpdateReportingControls(is_phishing_report); GetDialogClientView()->UpdateDialogButtons(); } @@ -334,13 +401,35 @@ bool BugReportView::Accept() { problem_type_, UTF16ToUTF8(page_url_text_->text()), UTF16ToUTF8(description_text_->text()), +#if defined(OS_CHROMEOS) + include_new_screen_image_radio_->checked() && png_data_.get() ? +#else include_page_image_checkbox_->checked() && png_data_.get() ? +#endif reinterpret_cast<const char *>(&((*png_data_.get())[0])) : NULL, - png_data_->size()); + png_data_->size(), screenshot_size_.width(), + screenshot_size_.height()); } return true; } +#if defined(OS_CHROMEOS) +void BugReportView::LinkActivated(views::Link* source, + int event_flags) { + GURL url; + if (source == system_information_url_) { + url = GURL(l10n_util::GetStringUTF16(IDS_BUGREPORT_SYSTEM_INFORMATION_URL)); + } else { + NOTREACHED() << "Unknown link source"; + return; + } + + Browser* browser = BrowserList::GetLastActive(); + browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); +} +#endif + + views::View* BugReportView::GetContentsView() { return this; } diff --git a/chrome/browser/views/bug_report_view.h b/chrome/browser/views/bug_report_view.h index 7d641b1..1fa3e5d 100644 --- a/chrome/browser/views/bug_report_view.h +++ b/chrome/browser/views/bug_report_view.h @@ -6,9 +6,13 @@ #define CHROME_BROWSER_VIEWS_BUG_REPORT_VIEW_H_ #include "chrome/common/net/url_fetcher.h" +#include "gfx/rect.h" #include "googleurl/src/gurl.h" +#include "views/controls/button/radio_button.h" #include "views/controls/combobox/combobox.h" #include "views/controls/textfield/textfield.h" +#include "views/controls/link.h" +#include "views/controls/image_view.h" #include "views/view.h" #include "views/window/dialog_delegate.h" @@ -17,6 +21,8 @@ class Checkbox; class Label; class Throbber; class Window; +class RadioButton; +class Link; } class Profile; @@ -35,6 +41,9 @@ class BugReportComboBoxModel; class BugReportView : public views::View, public views::DialogDelegate, public views::Combobox::Listener, +#if defined(OS_CHROMEOS) + public views::LinkController, +#endif public views::Textfield::Controller { public: explicit BugReportView(Profile* profile, TabContents* tab); @@ -44,6 +53,12 @@ class BugReportView : public views::View, void set_png_data(std::vector<unsigned char> *png_data) { png_data_.reset(png_data); }; + void set_screenshot_size(const gfx::Rect& screenshot_size) { + screenshot_size_ = screenshot_size; + }; + // Set all additional reporting controls to disabled + // if phishing report + void UpdateReportingControls(bool is_phishing_report); // Overridden from views::View: virtual gfx::Size GetPreferredSize(); @@ -58,6 +73,11 @@ class BugReportView : public views::View, virtual void ItemChanged(views::Combobox* combobox, int prev_index, int new_index); +#if defined(OS_CHROMEOS) + // Overridden from views::LinkController: + virtual void LinkActivated(views::Link* source, int event_flags); +#endif + // Overridden from views::DialogDelegate: virtual std::wstring GetDialogButtonLabel( MessageBoxFlags::DialogButton button) const; @@ -96,13 +116,23 @@ class BugReportView : public views::View, views::Label* description_label_; views::Textfield* description_text_; views::Checkbox* include_page_source_checkbox_; +#if defined(OS_CHROMEOS) + views::RadioButton* include_last_screen_image_radio_; + views::ImageView* last_screenshot_iv_; + views::RadioButton* include_new_screen_image_radio_; + views::Checkbox* include_system_information_checkbox_; + views::Link* system_information_url_; +#endif + // TODO: #else this once the BugReport function is fixed up views::Checkbox* include_page_image_checkbox_; + scoped_ptr<BugReportComboBoxModel> bug_type_model_; Profile* profile_; std::wstring version_; + gfx::Rect screenshot_size_; scoped_ptr< std::vector<unsigned char> > png_data_; TabContents* tab_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index b4c8817..6ebffd5 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -21,6 +21,7 @@ 'browser/sync/protocol/sync_proto.gyp:sync_proto_cpp', 'syncapi', 'theme_resources', + 'userfeedback_proto', '../app/app.gyp:app_resources', '../app/app.gyp:app_strings', '../media/media.gyp:media', @@ -298,6 +299,14 @@ 'browser/browsing_instance.h', 'browser/bug_report_util.cc', 'browser/bug_report_util.h', + # TODO(rkc): Find a better way to include these files + '<(protoc_out_dir)/chrome/browser/userfeedback/proto/annotations.pb.cc', + '<(protoc_out_dir)/chrome/browser/userfeedback/proto/common.pb.cc', + '<(protoc_out_dir)/chrome/browser/userfeedback/proto/config.pb.cc', + '<(protoc_out_dir)/chrome/browser/userfeedback/proto/dom.pb.cc', + '<(protoc_out_dir)/chrome/browser/userfeedback/proto/extension.pb.cc', + '<(protoc_out_dir)/chrome/browser/userfeedback/proto/math.pb.cc', + '<(protoc_out_dir)/chrome/browser/userfeedback/proto/web.pb.cc', 'browser/cancelable_request.cc', 'browser/cancelable_request.h', 'browser/cert_store.cc', @@ -3180,6 +3189,7 @@ ], 'dependencies': [ '../third_party/protobuf2/protobuf.gyp:protobuf_lite', + #'../third_party/protobuf2/protobuf.gyp:protobuf', '../third_party/protobuf2/protobuf.gyp:protoc#host', '../third_party/chromeos_login_manager/chromeos_login_manager/chromeos_login_manager.gyp:session', '../third_party/chromeos_login_manager/chromeos_login_manager/chromeos_login_manager.gyp:emit_login_prompt_ready', @@ -3428,6 +3438,61 @@ }, ] }, + { + # Protobuf compiler / generate rule for feedback + 'target_name': 'userfeedback_proto', + 'type': 'none', + 'sources': [ + 'browser/userfeedback/proto/annotations.proto', + 'browser/userfeedback/proto/common.proto', + 'browser/userfeedback/proto/config.proto', + 'browser/userfeedback/proto/dom.proto', + 'browser/userfeedback/proto/extension.proto', + 'browser/userfeedback/proto/math.proto', + 'browser/userfeedback/proto/web.proto', + ], + 'rules': [ + { + 'rule_name': 'genproto', + 'extension': 'proto', + 'inputs': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', + ], + 'variables': { + # The protoc compiler requires a proto_path argument with the + # directory containing the .proto file. + # There's no generator variable that corresponds to this, so fake it. + 'rule_input_relpath': 'browser/userfeedback/proto', + }, + 'outputs': [ + '<(protoc_out_dir)/chrome/<(rule_input_relpath)/<(RULE_INPUT_ROOT).pb.h', + '<(protoc_out_dir)/chrome/<(rule_input_relpath)/<(RULE_INPUT_ROOT).pb.cc', + ], + 'action': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', + '--proto_path=./<(rule_input_relpath)', + './<(rule_input_relpath)/<(RULE_INPUT_ROOT)<(RULE_INPUT_EXT)', + '--cpp_out=<(protoc_out_dir)/chrome/<(rule_input_relpath)', + ], + 'message': 'Generating C++ code from <(RULE_INPUT_PATH)', + }, + ], + 'dependencies': [ + '../third_party/protobuf2/protobuf.gyp:protobuf', + '../third_party/protobuf2/protobuf.gyp:protoc#host', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(protoc_out_dir)', + ] + }, + 'export_dependent_settings': [ + '../third_party/protobuf2/protobuf.gyp:protobuf', + ], + 'dependencies': [ + '../third_party/protobuf2/protobuf.gyp:protobuf', + ], + }, ], } diff --git a/third_party/protobuf2/protobuf.gyp b/third_party/protobuf2/protobuf.gyp index c812d52..c1a9e39 100644 --- a/third_party/protobuf2/protobuf.gyp +++ b/third_party/protobuf2/protobuf.gyp @@ -95,7 +95,7 @@ { 'target_name': 'protobuf', 'type': '<(library)', - 'toolsets': ['host'], + 'toolsets': ['host','target'], 'sources': [ 'src/src/google/protobuf/descriptor.h', 'src/src/google/protobuf/descriptor.pb.h', |