summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_no_faded.pngbin0 -> 4425 bytes
-rw-r--r--chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_no_pressed.pngbin0 -> 4342 bytes
-rw-r--r--chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_yes_faded.pngbin0 -> 5488 bytes
-rw-r--r--chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_yes_pressed.pngbin0 -> 5468 bytes
-rw-r--r--chrome/android/java/res/drawable/distillation_quality_answer_no.xml15
-rw-r--r--chrome/android/java/res/drawable/distillation_quality_answer_yes.xml15
-rw-r--r--chrome/android/java/res/layout/feedback_reporting_view.xml88
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/Tab.java6
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java2
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReporter.java150
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReportingView.java142
-rw-r--r--chrome/android/java/strings/android_chrome_strings.grd11
-rw-r--r--chrome/browser/android/chrome_jni_registrar.cc2
-rw-r--r--chrome/browser/android/dom_distiller/feedback_reporter_android.cc89
-rw-r--r--chrome/browser/android/dom_distiller/feedback_reporter_android.h55
-rw-r--r--chrome/chrome_browser.gypi3
-rw-r--r--components/dom_distiller.gypi2
-rw-r--r--components/dom_distiller/core/feedback_reporter.cc20
-rw-r--r--components/dom_distiller/core/feedback_reporter.h28
-rw-r--r--tools/metrics/histograms/histograms.xml6
20 files changed, 633 insertions, 1 deletions
diff --git a/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_no_faded.png b/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_no_faded.png
new file mode 100644
index 0000000..d969dd5
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_no_faded.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_no_pressed.png b/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_no_pressed.png
new file mode 100644
index 0000000..9c8db8f
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_no_pressed.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_yes_faded.png b/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_yes_faded.png
new file mode 100644
index 0000000..a0a7e3d
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_yes_faded.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_yes_pressed.png b/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_yes_pressed.png
new file mode 100644
index 0000000..8d1d3a1
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/distillation_quality_answer_yes_pressed.png
Binary files differ
diff --git a/chrome/android/java/res/drawable/distillation_quality_answer_no.xml b/chrome/android/java/res/drawable/distillation_quality_answer_no.xml
new file mode 100644
index 0000000..806192c
--- /dev/null
+++ b/chrome/android/java/res/drawable/distillation_quality_answer_no.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2014 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:state_focused="false"
+ android:drawable="@drawable/distillation_quality_answer_no_faded" />
+ <item
+ android:drawable="@drawable/distillation_quality_answer_no_pressed" />
+</selector>
diff --git a/chrome/android/java/res/drawable/distillation_quality_answer_yes.xml b/chrome/android/java/res/drawable/distillation_quality_answer_yes.xml
new file mode 100644
index 0000000..9fff3af
--- /dev/null
+++ b/chrome/android/java/res/drawable/distillation_quality_answer_yes.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2014 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:state_focused="false"
+ android:drawable="@drawable/distillation_quality_answer_yes_faded" />
+ <item
+ android:drawable="@drawable/distillation_quality_answer_yes_pressed" />
+</selector>
diff --git a/chrome/android/java/res/layout/feedback_reporting_view.xml b/chrome/android/java/res/layout/feedback_reporting_view.xml
new file mode 100644
index 0000000..6bbec5e
--- /dev/null
+++ b/chrome/android/java/res/layout/feedback_reporting_view.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2014 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<org.chromium.chrome.browser.dom_distiller.FeedbackReportingView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/feedback_reporting_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#656565">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:baselineAligned="false"
+ android:layout_width="match_parent"
+ android:layout_height="15dp"
+ android:orientation="horizontal">
+
+ <View
+ android:background="#4285F4"
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1" />
+
+ <View
+ android:background="#DB4437"
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1" />
+
+ <View
+ android:background="#F4B400"
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1" />
+
+ <View
+ android:background="#0F9D58"
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:orientation="horizontal">
+
+ <ImageButton
+ android:id="@+id/distillation_quality_answer_no"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/distillation_quality_answer_no"
+ android:background="@null"
+ android:src="@drawable/distillation_quality_answer_no" />
+
+ <TextView
+ android:id="@+id/distillation_quality_question"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:padding="10dp"
+ android:text="@string/distillation_quality_question"
+ android:textSize="20sp"
+ android:textColor="@android:color/white"
+ android:textStyle="bold"
+ android:fontFamily="sans-serif" />
+
+ <ImageButton
+ android:id="@+id/distillation_quality_answer_yes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/distillation_quality_answer_yes"
+ android:background="@null"
+ android:src="@drawable/distillation_quality_answer_yes" />
+
+ </LinearLayout>
+ </LinearLayout>
+
+</org.chromium.chrome.browser.dom_distiller.FeedbackReportingView> \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
index 62b54f4..eabf994 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
@@ -21,6 +21,7 @@ import org.chromium.chrome.browser.contextmenu.ContextMenuParams;
import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
import org.chromium.chrome.browser.contextmenu.ContextMenuPopulatorWrapper;
import org.chromium.chrome.browser.contextmenu.EmptyChromeContextMenuItemDelegate;
+import org.chromium.chrome.browser.dom_distiller.FeedbackReporter;
import org.chromium.chrome.browser.infobar.AutoLoginProcessor;
import org.chromium.chrome.browser.infobar.InfoBarContainer;
import org.chromium.chrome.browser.profiles.Profile;
@@ -128,6 +129,7 @@ public class Tab implements NavigationClient {
private WebContentsObserverAndroid mWebContentsObserver;
private VoiceSearchTabHelper mVoiceSearchTabHelper;
private TabChromeWebContentsDelegateAndroid mWebContentsDelegate;
+ private FeedbackReporter mFeedbackReporter;
/**
* A default {@link ChromeContextMenuItemDelegate} that supports some of the context menu
@@ -773,6 +775,10 @@ public class Tab implements NavigationClient {
mAppBannerManager = new AppBannerManager(this);
}
+ if (FeedbackReporter.isEnabled() && mFeedbackReporter == null) {
+ mFeedbackReporter = new FeedbackReporter(this);
+ }
+
for (TabObserver observer : mObservers) observer.onContentChanged(this);
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java
index dc6728c..ce3afbe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java
@@ -387,7 +387,7 @@ public abstract class SwipableOverlayView extends FrameLayout {
/**
* Dismisses the View, animating it moving vertically off of the screen if needed.
*/
- void dismiss() {
+ protected void dismiss() {
if (getParent() == null) return;
float translationY = mTotalHeight;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReporter.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReporter.java
new file mode 100644
index 0000000..072d6a4
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReporter.java
@@ -0,0 +1,150 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.dom_distiller;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.chrome.browser.EmptyTabObserver;
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.TabObserver;
+import org.chromium.content.browser.ContentView;
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * Java implementation of FeedbackReporterAndroid.
+ */
+@JNINamespace("dom_distiller::android")
+public final class FeedbackReporter implements FeedbackReportingView.FeedbackObserver {
+
+ private final long mNativePointer;
+ private final Tab mTab;
+ private ContentView mContentView;
+ private FeedbackReportingView mFeedbackReportingView;
+ private String mOverlayUrl;
+
+ /**
+ * @return whether the DOM Distiller feature is enabled.
+ */
+ public static boolean isEnabled() {
+ return nativeIsEnabled();
+ }
+
+ /**
+ * Records feedback for the distilled content.
+ *
+ * @param good whether the perceived quality of the distillation of a web page was good.
+ */
+ private static void recordQuality(boolean good) {
+ nativeReportQuality(good);
+ }
+
+ /**
+ * Creates the FeedbackReporter, adds itself as a TabObserver, and ensures
+ * references to ContentView and WebContents are up to date.
+ *
+ * @param tab the tab where the overlay should be displayed.
+ */
+ public FeedbackReporter(Tab tab) {
+ mNativePointer = nativeInit();
+ mTab = tab;
+ mTab.addObserver(createTabObserver());
+ updatePointers();
+ }
+
+ @Override
+ public void onYesPressed(FeedbackReportingView view) {
+ if (view != mFeedbackReportingView) return;
+ recordQuality(true);
+ dismissOverlay();
+ }
+
+ @Override
+ public void onNoPressed(FeedbackReportingView view) {
+ if (view != mFeedbackReportingView) return;
+ recordQuality(false);
+ dismissOverlay();
+ }
+
+ /**
+ * Start showing the overlay.
+ */
+ private void showOverlay() {
+ mFeedbackReportingView = FeedbackReportingView.create(mContentView, this);
+ }
+
+ @CalledByNative
+ private void dismissOverlay() {
+ if (mFeedbackReportingView != null) mFeedbackReportingView.dismiss();
+ mOverlayUrl = null;
+ mFeedbackReportingView = null;
+ }
+
+ /**
+ * Dismiss the overlay which is currently being displayed.
+ */
+ @CalledByNative
+ private String getCurrentOverlayUrl() {
+ return mOverlayUrl;
+ }
+
+ /**
+ * Updates which ContentView and WebContents the FeedbackReporter is monitoring.
+ */
+ private void updatePointers() {
+ mContentView = mTab.getContentView();
+ nativeReplaceWebContents(mNativePointer, mTab.getWebContents());
+ }
+
+ /**
+ * Creates a TabObserver for monitoring a Tab, used to react to changes in the ContentView
+ * or to trigger its own destruction.
+ *
+ * @return TabObserver that can be used to monitor a Tab.
+ */
+ private TabObserver createTabObserver() {
+ return new EmptyTabObserver() {
+ @Override
+ public void onWebContentsSwapped(Tab tab, boolean didStartLoad,
+ boolean didFinishLoad) {
+ updatePointers();
+ }
+
+ @Override
+ public void onContentChanged(Tab tab) {
+ updatePointers();
+ }
+
+ @Override
+ public void onUpdateUrl(Tab tab, String url) {
+ boolean reportable = nativeIsReportableUrl(url);
+ if (reportable) {
+ mOverlayUrl = url;
+ showOverlay();
+ } else {
+ dismissOverlay();
+ }
+ }
+
+ @Override
+ public void onDestroyed(Tab tab) {
+ nativeDestroy(mNativePointer);
+ mContentView = null;
+ }
+ };
+ }
+
+ private static native boolean nativeIsEnabled();
+
+ private static native boolean nativeIsReportableUrl(String url);
+
+ private static native void nativeReportQuality(boolean good);
+
+ private native long nativeInit();
+
+ private native void nativeDestroy(long nativeFeedbackReporterAndroid);
+
+ private native void nativeReplaceWebContents(
+ long nativeFeedbackReporterAndroid, WebContents webContents);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReportingView.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReportingView.java
new file mode 100644
index 0000000..59e178c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReportingView.java
@@ -0,0 +1,142 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.dom_distiller;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ImageButton;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.banners.SwipableOverlayView;
+import org.chromium.content.browser.ContentView;
+
+/**
+ * A view which displays a question to the user about the quality of distillation, where the user
+ * is given the option to respond.
+ *
+ * <p>The observer is called when the user makes a choice. After this point, it is not possible to
+ * interact with the view, and it is ready for dismissal. The selected option stays visibly
+ * selected.
+ */
+public class FeedbackReportingView extends SwipableOverlayView {
+ // XML layout for the BannerView.
+ private static final int VIEW_LAYOUT = R.layout.feedback_reporting_view;
+
+ // Class to alert about FeedbackReportingView events.
+ private FeedbackObserver mFeedbackObserver;
+
+ // The button to click for selecting 'No'.
+ private ImageButton mNoButton;
+
+ // The button to click for selecting 'Yes'.
+ private ImageButton mYesButton;
+
+ // Whether a selection has already been made, which means new events should be ignored.
+ private boolean mSelectionMade;
+
+ /**
+ * Called when the user makes a choice. After the call, it is not possible to interact further
+ * with the view.
+ */
+ interface FeedbackObserver {
+ void onYesPressed(FeedbackReportingView view);
+
+ void onNoPressed(FeedbackReportingView view);
+ }
+
+ /**
+ * Creates a FeedbackReportingView and adds it to the given ContentView.
+ *
+ * @param contentView ContentView to display the FeedbackReportingView for.
+ * @param feedbackObserver Class that is alerted for FeedbackReportingView events.
+ * @return The created banner.
+ */
+ public static FeedbackReportingView create(ContentView contentView,
+ FeedbackObserver feedbackObserver) {
+ Context context = contentView.getContext().getApplicationContext();
+ FeedbackReportingView banner =
+ (FeedbackReportingView) LayoutInflater.from(context).inflate(VIEW_LAYOUT, null);
+ banner.initialize(feedbackObserver);
+ banner.addToView(contentView);
+ return banner;
+ }
+
+ /**
+ * Creates a FeedbackReportingView.
+ *
+ * @param context Context for acquiring resources.
+ * @param attrs Attributes from the XML layout inflation.
+ */
+ public FeedbackReportingView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ private void initialize(FeedbackObserver feedbackObserver) {
+ mFeedbackObserver = feedbackObserver;
+ mNoButton = (ImageButton) findViewById(R.id.distillation_quality_answer_no);
+ mYesButton = (ImageButton) findViewById(R.id.distillation_quality_answer_yes);
+ mNoButton.setClickable(true);
+ mYesButton.setClickable(true);
+ mNoButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mSelectionMade) return;
+ mSelectionMade = true;
+ mNoButton.setImageResource(R.drawable.distillation_quality_answer_no_pressed);
+ disableUI();
+ if (mFeedbackObserver != null) {
+ mFeedbackObserver.onNoPressed(FeedbackReportingView.this);
+ }
+ }
+ });
+ mYesButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mSelectionMade) return;
+ mSelectionMade = true;
+ mYesButton.setImageResource(R.drawable.distillation_quality_answer_yes_pressed);
+ disableUI();
+ if (mFeedbackObserver != null) {
+ mFeedbackObserver.onYesPressed(FeedbackReportingView.this);
+ }
+ }
+ });
+ }
+
+ private void disableUI() {
+ // Clear OnClickListener to assure no more calls and that everything is cleaned up.
+ mNoButton.setOnClickListener(null);
+ mYesButton.setOnClickListener(null);
+
+ // Disable the buttons, so the images for highlighted/non-highlighted will not change if the
+ // user continues to tap the buttons while it is dismissing.
+ mNoButton.setEnabled(false);
+ mYesButton.setEnabled(false);
+ }
+
+ /**
+ * This is overridden since the method visibility is protected in the parent
+ * {@link SwipableOverlayView}. The
+ * {@link org.chromium.chrome.browser.dom_distiller.FeedbackReporter} needs to be able to
+ * dismiss this {@link org.chromium.chrome.browser.dom_distiller.FeedbackReportingView}, so by
+ * overriding this method in this class, it is callable from
+ * {@link org.chromium.chrome.browser.dom_distiller.FeedbackReporter}.
+ */
+ @Override
+ protected void dismiss() {
+ super.dismiss();
+ }
+
+ @Override
+ protected void onViewClicked() {
+ }
+
+ @Override
+ protected void onViewPressed(MotionEvent event) {
+ }
+}
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 9fd1e0c..1026390 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -283,6 +283,17 @@ You are signing in with a managed account and giving its administrator control o
<message name="IDS_APP_BANNER_OPEN" desc="Text that indicates that clicking on the button will launch an application.">
Open
</message>
+
+ <!-- DOM Distiller strings -->
+ <message name="IDS_DISTILLATION_QUALITY_QUESTION" desc="Question to ask the user about whether the text from a web page was extracted correctly.">
+ Was the text extracted correctly?
+ </message>
+ <message name="IDS_DISTILLATION_QUALITY_ANSWER_YES" desc="Text for the answering whether the text from a web page was extracted correctly and the answer is yes.">
+ Yes
+ </message>
+ <message name="IDS_DISTILLATION_QUALITY_ANSWER_NO" desc="Text for the answering whether the text from a web page was extracted correctly and the answer is no.">
+ No
+ </message>
</messages>
</release>
</grit>
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 1c4b0b8..38f28b3 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/android/chromium_application.h"
#include "chrome/browser/android/content_view_util.h"
#include "chrome/browser/android/dev_tools_server.h"
+#include "chrome/browser/android/dom_distiller/feedback_reporter_android.h"
#include "chrome/browser/android/favicon_helper.h"
#include "chrome/browser/android/field_trial_helper.h"
#include "chrome/browser/android/foreign_session_helper.h"
@@ -119,6 +120,7 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = {
prerender::ExternalPrerenderHandlerAndroid::
RegisterExternalPrerenderHandlerAndroid },
{ "FaviconHelper", FaviconHelper::RegisterFaviconHelper },
+ { "FeedbackReporter", dom_distiller::android::RegisterFeedbackReporter },
{ "FieldTrialHelper", RegisterFieldTrialHelper },
{ "ForeignSessionHelper",
ForeignSessionHelper::RegisterForeignSessionHelper },
diff --git a/chrome/browser/android/dom_distiller/feedback_reporter_android.cc b/chrome/browser/android/dom_distiller/feedback_reporter_android.cc
new file mode 100644
index 0000000..37867bb
--- /dev/null
+++ b/chrome/browser/android/dom_distiller/feedback_reporter_android.cc
@@ -0,0 +1,89 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/dom_distiller/feedback_reporter_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/url_constants.h"
+#include "components/dom_distiller/core/feedback_reporter.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/frame_navigate_params.h"
+#include "jni/FeedbackReporter_jni.h"
+#include "url/gurl.h"
+
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+
+namespace dom_distiller {
+
+namespace android {
+
+// static
+jboolean IsEnabled(JNIEnv* env, jclass clazz) {
+ return CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableDomDistiller);
+}
+
+// static
+void ReportQuality(JNIEnv* env, jclass clazz, jboolean j_good) {
+ FeedbackReporter::ReportQuality(j_good);
+}
+
+// static
+jboolean IsReportableUrl(JNIEnv* env, jclass clazz, jstring j_url_str) {
+ const std::string url_str = ConvertJavaStringToUTF8(env, j_url_str);
+ const GURL url(url_str);
+ if (!url.is_valid())
+ return false;
+ return url.scheme() == chrome::kDomDistillerScheme;
+}
+
+FeedbackReporterAndroid::FeedbackReporterAndroid(JNIEnv* env, jobject obj)
+ : weak_java_feedback_reporter_(env, obj) {}
+
+FeedbackReporterAndroid::~FeedbackReporterAndroid() {}
+
+void FeedbackReporterAndroid::Destroy(JNIEnv* env, jobject obj) { delete this; }
+
+void FeedbackReporterAndroid::ReplaceWebContents(JNIEnv* env,
+ jobject obj,
+ jobject jweb_contents) {
+ content::WebContents* web_contents =
+ content::WebContents::FromJavaWebContents(jweb_contents);
+ Observe(web_contents);
+}
+
+void FeedbackReporterAndroid::DidNavigateMainFrame(
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> jobj = weak_java_feedback_reporter_.get(env);
+ if (jobj.is_null())
+ return;
+ base::android::ScopedJavaLocalRef<jstring> j_current_overlay_url_str =
+ Java_FeedbackReporter_getCurrentOverlayUrl(env, jobj.obj());
+ std::string current_overlay_url_str =
+ ConvertJavaStringToUTF8(j_current_overlay_url_str);
+ GURL current_overlay_url(current_overlay_url_str);
+ GURL navigation_url = details.entry->GetURL();
+ if (!current_overlay_url.is_valid() || navigation_url != current_overlay_url)
+ Java_FeedbackReporter_dismissOverlay(env, jobj.obj());
+}
+
+jlong Init(JNIEnv* env, jobject obj) {
+ FeedbackReporterAndroid* reporter = new FeedbackReporterAndroid(env, obj);
+ return reinterpret_cast<intptr_t>(reporter);
+}
+
+// static
+bool RegisterFeedbackReporter(JNIEnv* env) { return RegisterNativesImpl(env); }
+
+} // namespace android
+
+} // namespace dom_distiller
diff --git a/chrome/browser/android/dom_distiller/feedback_reporter_android.h b/chrome/browser/android/dom_distiller/feedback_reporter_android.h
new file mode 100644
index 0000000..3d2d462
--- /dev/null
+++ b/chrome/browser/android/dom_distiller/feedback_reporter_android.h
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_DOM_DISTILLER_FEEDBACK_REPORTER_ANDROID_H_
+#define CHROME_BROWSER_ANDROID_DOM_DISTILLER_FEEDBACK_REPORTER_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/android/jni_helper.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+struct FrameNavigateParams;
+struct LoadCommittedDetails;
+} // namespace content
+
+namespace dom_distiller {
+
+namespace android {
+
+class FeedbackReporterAndroid : content::WebContentsObserver {
+ public:
+ FeedbackReporterAndroid(JNIEnv* env, jobject obj);
+ virtual ~FeedbackReporterAndroid();
+
+ // Destroys the FeedbackReporterAndroid.
+ void Destroy(JNIEnv* env, jobject obj);
+
+ // Observes a new WebContents, if necessary.
+ void ReplaceWebContents(JNIEnv* env, jobject obj, jobject jweb_contents);
+
+ // WebContentsObserver implementation:
+ virtual void DidNavigateMainFrame(
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) OVERRIDE;
+
+ static jboolean IsReportableUrl(JNIEnv* env, jclass clazz);
+
+ private:
+ // FeedbackReporterAndroid on the Java side.
+ JavaObjectWeakGlobalRef weak_java_feedback_reporter_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeedbackReporterAndroid);
+};
+
+// Registers the FeedbackReporter's native methods through JNI.
+bool RegisterFeedbackReporter(JNIEnv* env);
+
+} // namespace android
+
+} // namespace dom_distiller
+
+#endif // CHROME_BROWSER_ANDROID_DOM_DISTILLER_FEEDBACK_REPORTER_ANDROID_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 3727bf0..b261c20 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -140,6 +140,8 @@
'browser/android/content_view_util.h',
'browser/android/dev_tools_server.cc',
'browser/android/dev_tools_server.h',
+ 'browser/android/dom_distiller/feedback_reporter_android.cc',
+ 'browser/android/dom_distiller/feedback_reporter_android.h',
'browser/android/favicon_helper.cc',
'browser/android/favicon_helper.h',
'browser/android/field_trial_helper.cc',
@@ -3740,6 +3742,7 @@
'android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuParams.java',
'android/java/src/org/chromium/chrome/browser/DevToolsServer.java',
'android/java/src/org/chromium/chrome/browser/database/SQLiteCursor.java',
+ 'android/java/src/org/chromium/chrome/browser/dom_distiller/FeedbackReporter.java',
'android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java',
'android/java/src/org/chromium/chrome/browser/FieldTrialHelper.java',
'android/java/src/org/chromium/chrome/browser/ForeignSessionHelper.java',
diff --git a/components/dom_distiller.gypi b/components/dom_distiller.gypi
index 5ac311e..2c9e45e 100644
--- a/components/dom_distiller.gypi
+++ b/components/dom_distiller.gypi
@@ -71,6 +71,8 @@
'dom_distiller/core/dom_distiller_service.h',
'dom_distiller/core/dom_distiller_store.cc',
'dom_distiller/core/dom_distiller_store.h',
+ 'dom_distiller/core/feedback_reporter.cc',
+ 'dom_distiller/core/feedback_reporter.h',
'dom_distiller/core/page_distiller.cc',
'dom_distiller/core/page_distiller.h',
'dom_distiller/core/task_tracker.cc',
diff --git a/components/dom_distiller/core/feedback_reporter.cc b/components/dom_distiller/core/feedback_reporter.cc
new file mode 100644
index 0000000..a536ef7
--- /dev/null
+++ b/components/dom_distiller/core/feedback_reporter.cc
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/dom_distiller/core/feedback_reporter.h"
+
+#include "base/metrics/histogram.h"
+
+namespace dom_distiller {
+
+FeedbackReporter::FeedbackReporter() {}
+
+FeedbackReporter::~FeedbackReporter() {}
+
+// static
+void FeedbackReporter::ReportQuality(bool good) {
+ UMA_HISTOGRAM_BOOLEAN("DomDistiller.DistillationQuality", good);
+}
+
+} // namespace dom_distiller
diff --git a/components/dom_distiller/core/feedback_reporter.h b/components/dom_distiller/core/feedback_reporter.h
new file mode 100644
index 0000000..9802530
--- /dev/null
+++ b/components/dom_distiller/core/feedback_reporter.h
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOM_DISTILLER_CORE_FEEDBACK_REPORTER_H_
+#define COMPONENTS_DOM_DISTILLER_CORE_FEEDBACK_REPORTER_H_
+
+#include "base/macros.h"
+
+namespace dom_distiller {
+
+// FeedbackReporter handles reporting distillation quality.
+class FeedbackReporter {
+ public:
+ FeedbackReporter();
+ virtual ~FeedbackReporter();
+
+ // Reports the quality of the distillation. |good| represents whether the
+ // perceived quality of the distillation of a web page was good.
+ static void ReportQuality(bool good);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FeedbackReporter);
+};
+
+} // namespace dom_distiller
+
+#endif // COMPONENTS_DOM_DISTILLER_CORE_FEEDBACK_REPORTER_H_
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 055f7e7..41e9f8c 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -3163,6 +3163,12 @@ other types of suffix sets.
</summary>
</histogram>
+<histogram name="DomDistiller.DistillationQuality" enum="BooleanSuccess">
+ <summary>
+ Whether the perceived quality of the distillation of a web page was good.
+ </summary>
+</histogram>
+
<histogram name="Download.AcceptRangesBytes.KBytes" units="KB">
<summary>The length of downloads for serves that accept byte ranges.</summary>
</histogram>