Commit 564da6d9 authored by Michael Bai's avatar Michael Bai Committed by Commit Bot

Make ContentCapture ready for experiment

Currently the triggering of ContentCapture is unpredictable, it is
hard for us to get the unbiased result for the UserActivatedDelay
experiment.

This patch adds an ExperimentContentCaptureConsumer which triggers
the ContentCapture independently and is enabled by default.

The allow list check is moved to consumer if the experiment
is enabled.

As ContentCapture is potentially used for all Android versions,
we plan to run the experiment for all of them.

This mechanism will also be used for future experiments.

This patch hasn't supported multiple consumers yet.

Test: Added new tests and pass the existing tests

Bug: 1114819, 1119663
Change-Id: I72e0b991767329caec37080caae2d5c2a9068eaf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2368104
Commit-Queue: Tao Bai <michaelbai@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarChangwan Ryu <changwan@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#801672}
parent 7cde8a65
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.android_webview.test; package org.chromium.android_webview.test;
import android.graphics.Rect; import android.graphics.Rect;
import android.net.Uri;
import androidx.test.filters.LargeTest; import androidx.test.filters.LargeTest;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
...@@ -23,6 +24,7 @@ import org.chromium.base.test.util.Feature; ...@@ -23,6 +24,7 @@ import org.chromium.base.test.util.Feature;
import org.chromium.components.content_capture.ContentCaptureConsumer; import org.chromium.components.content_capture.ContentCaptureConsumer;
import org.chromium.components.content_capture.ContentCaptureController; import org.chromium.components.content_capture.ContentCaptureController;
import org.chromium.components.content_capture.ContentCaptureData; import org.chromium.components.content_capture.ContentCaptureData;
import org.chromium.components.content_capture.ExperimentContentCaptureConsumer;
import org.chromium.components.content_capture.FrameSession; import org.chromium.components.content_capture.FrameSession;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
...@@ -57,6 +59,7 @@ public class AwContentCaptureTest { ...@@ -57,6 +59,7 @@ public class AwContentCaptureTest {
String[] allowlist = null; String[] allowlist = null;
boolean[] isRegEx = null; boolean[] isRegEx = null;
if (mAllowlist != null && mIsRegEx != null) { if (mAllowlist != null && mIsRegEx != null) {
allowlist = new String[mAllowlist.size()];
mAllowlist.toArray(allowlist); mAllowlist.toArray(allowlist);
isRegEx = new boolean[mAllowlist.size()]; isRegEx = new boolean[mAllowlist.size()];
int i = 0; int i = 0;
...@@ -67,6 +70,13 @@ public class AwContentCaptureTest { ...@@ -67,6 +70,13 @@ public class AwContentCaptureTest {
setAllowlist(allowlist, isRegEx); setAllowlist(allowlist, isRegEx);
} }
public void setAllowURL(String host) {
mAllowlist = new ArrayList<String>();
mAllowlist.add(host);
mIsRegEx = new ArrayList<Boolean>();
mIsRegEx.add(Boolean.FALSE);
}
private ArrayList<String> mAllowlist; private ArrayList<String> mAllowlist;
private ArrayList<Boolean> mIsRegEx; private ArrayList<Boolean> mIsRegEx;
} }
...@@ -84,6 +94,10 @@ public class AwContentCaptureTest { ...@@ -84,6 +94,10 @@ public class AwContentCaptureTest {
mCapturedContentIds = new HashSet<Long>(); mCapturedContentIds = new HashSet<Long>();
} }
public void setContentCaptureController(ContentCaptureController controller) {
mController = controller;
}
@Override @Override
public void onContentCaptured( public void onContentCaptured(
FrameSession parentFrame, ContentCaptureData contentCaptureData) { FrameSession parentFrame, ContentCaptureData contentCaptureData) {
...@@ -124,6 +138,12 @@ public class AwContentCaptureTest { ...@@ -124,6 +138,12 @@ public class AwContentCaptureTest {
mCallbackHelper.notifyCalled(); mCallbackHelper.notifyCalled();
} }
@Override
public boolean shouldCapture(String[] urls) {
if (mController == null) return true;
return mController.shouldCapture(urls);
}
public FrameSession getParentFrame() { public FrameSession getParentFrame() {
return mParentFrame; return mParentFrame;
} }
...@@ -187,6 +207,7 @@ public class AwContentCaptureTest { ...@@ -187,6 +207,7 @@ public class AwContentCaptureTest {
// Use our own call count to avoid unexpected callback issue. // Use our own call count to avoid unexpected callback issue.
private int mCallCount; private int mCallCount;
// TODO: (crbug.com/1121827) Remove volatile if possible.
private volatile Set<Long> mCapturedContentIds; private volatile Set<Long> mCapturedContentIds;
private volatile FrameSession mParentFrame; private volatile FrameSession mParentFrame;
private volatile ContentCaptureData mCapturedContent; private volatile ContentCaptureData mCapturedContent;
...@@ -197,6 +218,7 @@ public class AwContentCaptureTest { ...@@ -197,6 +218,7 @@ public class AwContentCaptureTest {
private volatile ArrayList<Integer> mCallbacks = new ArrayList<Integer>(); private volatile ArrayList<Integer> mCallbacks = new ArrayList<Integer>();
private CallbackHelper mCallbackHelper = new CallbackHelper(); private CallbackHelper mCallbackHelper = new CallbackHelper();
private volatile ContentCaptureController mController;
} }
private static final String MAIN_FRAME_FILE = "/main_frame.html"; private static final String MAIN_FRAME_FILE = "/main_frame.html";
...@@ -212,6 +234,7 @@ public class AwContentCaptureTest { ...@@ -212,6 +234,7 @@ public class AwContentCaptureTest {
private AwTestContainerView mContainerView; private AwTestContainerView mContainerView;
private TestAwContentCaptureConsumer mConsumer; private TestAwContentCaptureConsumer mConsumer;
private TestAwContentCatpureController mController; private TestAwContentCatpureController mController;
private TestAwContentCaptureConsumer mSecondConsumer;
private void loadUrlSync(String url) { private void loadUrlSync(String url) {
try { try {
...@@ -582,4 +605,86 @@ public class AwContentCaptureTest { ...@@ -582,4 +605,86 @@ public class AwContentCaptureTest {
}, toIntArray(TestAwContentCaptureConsumer.SESSION_REMOVED)); }, toIntArray(TestAwContentCaptureConsumer.SESSION_REMOVED));
verifyFrameSession(removedSession, mConsumer.getRemovedSession()); verifyFrameSession(removedSession, mConsumer.getRemovedSession());
} }
@Test
@SmallTest
@Feature({"AndroidWebView"})
public void testMultipleConsumers() throws Throwable {
TestThreadUtils.runOnUiThreadBlocking(() -> {
mSecondConsumer = new TestAwContentCaptureConsumer(mAwContents.getWebContents());
});
final String response = "<html><head></head><body>"
+ "<div id='place_holder'>"
+ "<p style=\"height: 100vh\">Hello</p>"
+ "<p>world</p>"
+ "</body></html>";
final String url = mWebServer.setResponse(MAIN_FRAME_FILE, response, null);
runAndVerifyCallbacks(() -> {
loadUrlSync(url);
}, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
// Verify the other one also get the content.
verifyCallbacks(toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED),
mSecondConsumer.getCallbacks());
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add({"enable-features=ContentCaptureTriggeringForExperiment"})
public void testHostNotAllowed() throws Throwable {
TestThreadUtils.runOnUiThreadBlocking(() -> {
mSecondConsumer = new TestAwContentCaptureConsumer(mAwContents.getWebContents());
});
final String response = "<html><head></head><body>"
+ "<div id='place_holder'>"
+ "<p style=\"height: 100vh\">Hello</p>"
+ "<p>world</p>"
+ "</body></html>";
final String url = mWebServer.setResponse(MAIN_FRAME_FILE, response, null);
mController.setAllowURL("www.chromium.org");
mSecondConsumer.setContentCaptureController(mController);
runAndVerifyCallbacks(() -> {
loadUrlSync(url);
}, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
// Verify the other one didn't get the content.
Assert.assertEquals(0, mSecondConsumer.getCallbacks().length);
}
private void runHostAllowedTest() throws Throwable {
final String response = "<html><head></head><body>"
+ "<div id='place_holder'>"
+ "<p style=\"height: 100vh\">Hello</p>"
+ "<p>world</p>"
+ "</body></html>";
final String url = mWebServer.setResponse(MAIN_FRAME_FILE, response, null);
mController.setAllowURL(Uri.parse(url).getHost());
mConsumer.setContentCaptureController(mController);
runAndVerifyCallbacks(() -> {
loadUrlSync(url);
}, toIntArray(TestAwContentCaptureConsumer.CONTENT_CAPTURED));
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add({"disable-features=ContentCaptureTriggeringForExperiment"})
public void testHostAllowed() throws Throwable {
runHostAllowedTest();
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add({"enable-features=ContentCaptureTriggeringForExperiment"})
public void testHostAllowedForExperiment() throws Throwable {
runHostAllowedTest();
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add({"disable-features=ContentCaptureTriggeringForExperiment"})
public void testCantCreateExperimentConsumer() throws Throwable {
Assert.assertNull(ExperimentContentCaptureConsumer.create(mAwContents.getWebContents()));
}
} }
...@@ -71,6 +71,7 @@ import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; ...@@ -71,6 +71,7 @@ import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
import org.chromium.components.browser_ui.widget.InsetObserverView; import org.chromium.components.browser_ui.widget.InsetObserverView;
import org.chromium.components.content_capture.ContentCaptureConsumer; import org.chromium.components.content_capture.ContentCaptureConsumer;
import org.chromium.components.content_capture.ContentCaptureConsumerImpl; import org.chromium.components.content_capture.ContentCaptureConsumerImpl;
import org.chromium.components.content_capture.ExperimentContentCaptureConsumer;
import org.chromium.components.embedder_support.view.ContentView; import org.chromium.components.embedder_support.view.ContentView;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.KeyboardVisibilityDelegate; import org.chromium.ui.KeyboardVisibilityDelegate;
...@@ -189,7 +190,9 @@ public class CompositorViewHolder extends FrameLayout ...@@ -189,7 +190,9 @@ public class CompositorViewHolder extends FrameLayout
// Indicates if ContentCaptureConsumer should be created, we only try to create it once. // Indicates if ContentCaptureConsumer should be created, we only try to create it once.
private boolean mShouldCreateContentCaptureConsumer = true; private boolean mShouldCreateContentCaptureConsumer = true;
private ContentCaptureConsumer mContentCaptureConsumer; // TODO: (crbug.com/1119663) Move consumers out of this class while support multiple consumers.
private ArrayList<ContentCaptureConsumer> mContentCaptureConsumers =
new ArrayList<ContentCaptureConsumer>();
private Set<Runnable> mOnCompositorLayoutCallbacks = new HashSet<>(); private Set<Runnable> mOnCompositorLayoutCallbacks = new HashSet<>();
private Set<Runnable> mDidSwapFrameCallbacks = new HashSet<>(); private Set<Runnable> mDidSwapFrameCallbacks = new HashSet<>();
...@@ -533,10 +536,10 @@ public class CompositorViewHolder extends FrameLayout ...@@ -533,10 +536,10 @@ public class CompositorViewHolder extends FrameLayout
mInsetObserverView.removeObserver(this); mInsetObserverView.removeObserver(this);
mInsetObserverView = null; mInsetObserverView = null;
} }
if (mContentCaptureConsumer != null) { for (ContentCaptureConsumer consumer : mContentCaptureConsumers) {
mContentCaptureConsumer.onWebContentsChanged(null); consumer.onWebContentsChanged(null);
mContentCaptureConsumer = null;
} }
mContentCaptureConsumers.clear();
if (mContentView != null) { if (mContentView != null) {
mContentView.removeOnHierarchyChangeListener(this); mContentView.removeOnHierarchyChangeListener(this);
} }
...@@ -1320,15 +1323,20 @@ public class CompositorViewHolder extends FrameLayout ...@@ -1320,15 +1323,20 @@ public class CompositorViewHolder extends FrameLayout
if (mTabVisible != null) initializeTab(mTabVisible); if (mTabVisible != null) initializeTab(mTabVisible);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (mShouldCreateContentCaptureConsumer) {
if (mShouldCreateContentCaptureConsumer) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mContentCaptureConsumer = ContentCaptureConsumer consumer =
ContentCaptureConsumerImpl.create(getContext(), this, getWebContents()); ContentCaptureConsumerImpl.create(getContext(), this, getWebContents());
mShouldCreateContentCaptureConsumer = false; if (consumer != null) mContentCaptureConsumers.add(consumer);
}
ContentCaptureConsumer consumer =
ExperimentContentCaptureConsumer.create(getWebContents());
if (consumer != null) mContentCaptureConsumers.add(consumer);
mShouldCreateContentCaptureConsumer = false;
} else {
for (ContentCaptureConsumer consumer : mContentCaptureConsumers) {
consumer.onWebContentsChanged(getWebContents());
} }
}
if (mContentCaptureConsumer != null) {
mContentCaptureConsumer.onWebContentsChanged(getWebContents());
} }
} }
......
...@@ -38,6 +38,7 @@ android_library("java") { ...@@ -38,6 +38,7 @@ android_library("java") {
"java/src/org/chromium/components/content_capture/ContentCapturedTask.java", "java/src/org/chromium/components/content_capture/ContentCapturedTask.java",
"java/src/org/chromium/components/content_capture/ContentRemovedTask.java", "java/src/org/chromium/components/content_capture/ContentRemovedTask.java",
"java/src/org/chromium/components/content_capture/ContentUpdateTask.java", "java/src/org/chromium/components/content_capture/ContentUpdateTask.java",
"java/src/org/chromium/components/content_capture/ExperimentContentCaptureConsumer.java",
"java/src/org/chromium/components/content_capture/FrameSession.java", "java/src/org/chromium/components/content_capture/FrameSession.java",
"java/src/org/chromium/components/content_capture/NotificationTask.java", "java/src/org/chromium/components/content_capture/NotificationTask.java",
"java/src/org/chromium/components/content_capture/PlatformSession.java", "java/src/org/chromium/components/content_capture/PlatformSession.java",
......
...@@ -93,4 +93,17 @@ bool ContentCaptureController::ShouldCapture(const GURL& url) { ...@@ -93,4 +93,17 @@ bool ContentCaptureController::ShouldCapture(const GURL& url) {
return false; return false;
} }
bool ContentCaptureController::ShouldCapture(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
const base::android::JavaParamRef<jobjectArray>& urls) {
std::vector<base::string16> url_list;
AppendJavaStringArrayToStringVector(env, urls, &url_list);
for (auto url : url_list) {
if (!ShouldCapture(GURL(url)))
return false;
}
return true;
}
} // namespace content_capture } // namespace content_capture
...@@ -35,6 +35,9 @@ class ContentCaptureController { ...@@ -35,6 +35,9 @@ class ContentCaptureController {
const base::android::JavaParamRef<jbooleanArray>& jtype); const base::android::JavaParamRef<jbooleanArray>& jtype);
void SetJavaPeer(JNIEnv* env, void SetJavaPeer(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller); const base::android::JavaParamRef<jobject>& jcaller);
bool ShouldCapture(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
const base::android::JavaParamRef<jobjectArray>& urls);
private: private:
virtual ~ContentCaptureController(); virtual ~ContentCaptureController();
......
...@@ -8,3 +8,9 @@ ...@@ -8,3 +8,9 @@
static jboolean JNI_ContentCaptureFeatures_IsEnabled(JNIEnv* env) { static jboolean JNI_ContentCaptureFeatures_IsEnabled(JNIEnv* env) {
return content_capture::features::IsContentCaptureEnabled(); return content_capture::features::IsContentCaptureEnabled();
} }
static jboolean
JNI_ContentCaptureFeatures_ShouldTriggerContentCaptureForExperiment(
JNIEnv* env) {
return content_capture::features::ShouldTriggerContentCaptureForExperiment();
}
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "components/content_capture/android/content_capture_controller.h" #include "components/content_capture/android/content_capture_controller.h"
#include "components/content_capture/android/jni_headers/ContentCaptureData_jni.h" #include "components/content_capture/android/jni_headers/ContentCaptureData_jni.h"
#include "components/content_capture/android/jni_headers/ContentCaptureReceiverManager_jni.h" #include "components/content_capture/android/jni_headers/ContentCaptureReceiverManager_jni.h"
#include "components/content_capture/common/content_capture_features.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
using base::android::AttachCurrentThread; using base::android::AttachCurrentThread;
...@@ -147,6 +148,11 @@ void ContentCaptureReceiverManagerAndroid::DidRemoveSession( ...@@ -147,6 +148,11 @@ void ContentCaptureReceiverManagerAndroid::DidRemoveSession(
} }
bool ContentCaptureReceiverManagerAndroid::ShouldCapture(const GURL& url) { bool ContentCaptureReceiverManagerAndroid::ShouldCapture(const GURL& url) {
// Capture all urls for experiment, the url will be checked
// before the content is sent to the consumers.
if (features::ShouldTriggerContentCaptureForExperiment())
return true;
return ContentCaptureController::Get()->ShouldCapture(url); return ContentCaptureController::Get()->ShouldCapture(url);
} }
......
...@@ -50,9 +50,13 @@ public abstract class ContentCaptureConsumer { ...@@ -50,9 +50,13 @@ public abstract class ContentCaptureConsumer {
// of the removal of session. // of the removal of session.
if (current != null) { if (current != null) {
mManager = ContentCaptureReceiverManager.createOrGet(current); mManager = ContentCaptureReceiverManager.createOrGet(current);
mManager.setContentCaptureConsumer(this); mManager.addContentCaptureConsumer(this);
} else { } else {
mManager = null; mManager = null;
} }
} }
protected boolean shouldCapture(String[] urls) {
return true;
}
} }
...@@ -89,4 +89,14 @@ public class ContentCaptureConsumerImpl extends ContentCaptureConsumer { ...@@ -89,4 +89,14 @@ public class ContentCaptureConsumerImpl extends ContentCaptureConsumer {
new ContentRemovedTask(frame, removedIds, mPlatformSession) new ContentRemovedTask(frame, removedIds, mPlatformSession)
.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); .executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
} }
@Override
protected boolean shouldCapture(String[] urls) {
// No need to check if the experiment is disabled, because it was done when the navigation
// committed, refer to ContentCaptureReceiverManager::ReadyToCommitNavigation().
if (!ContentCaptureFeatures.shouldTriggerContentCaptureForExperiment()) return true;
ContentCaptureController controller = ContentCaptureController.getInstance();
if (controller == null) return false;
return controller.shouldCapture(urls);
}
} }
...@@ -44,6 +44,15 @@ public abstract class ContentCaptureController { ...@@ -44,6 +44,15 @@ public abstract class ContentCaptureController {
*/ */
public void clearContentCaptureDataForURLs(String[] urlsToDelete) {} public void clearContentCaptureDataForURLs(String[] urlsToDelete) {}
/**
* @param urls the urls need to check.
* @return if the content of all urls should be captured.
*/
public boolean shouldCapture(String[] urls) {
return ContentCaptureControllerJni.get().shouldCapture(
mNativeContentCaptureController, ContentCaptureController.this, urls);
}
/** /**
* Invoked by native side to pull the allowlist, the subclass should implement this and set * Invoked by native side to pull the allowlist, the subclass should implement this and set
* the allowlist by call setAllowlist. * the allowlist by call setAllowlist.
...@@ -69,5 +78,7 @@ public abstract class ContentCaptureController { ...@@ -69,5 +78,7 @@ public abstract class ContentCaptureController {
long init(Object contentCaptureController); long init(Object contentCaptureController);
void setAllowlist(long nativeContentCaptureController, ContentCaptureController caller, void setAllowlist(long nativeContentCaptureController, ContentCaptureController caller,
String[] allowlist, boolean[] isRegex); String[] allowlist, boolean[] isRegex);
boolean shouldCapture(long nativeContentCaptureController, ContentCaptureController caller,
String[] urls);
} }
} }
...@@ -20,8 +20,13 @@ public class ContentCaptureFeatures { ...@@ -20,8 +20,13 @@ public class ContentCaptureFeatures {
return CommandLine.getInstance().hasSwitch(FLAG); return CommandLine.getInstance().hasSwitch(FLAG);
} }
public static boolean shouldTriggerContentCaptureForExperiment() {
return ContentCaptureFeaturesJni.get().shouldTriggerContentCaptureForExperiment();
}
@NativeMethods @NativeMethods
interface Natives { interface Natives {
boolean isEnabled(); boolean isEnabled();
boolean shouldTriggerContentCaptureForExperiment();
} }
} }
...@@ -9,6 +9,7 @@ import org.chromium.base.annotations.CalledByNative; ...@@ -9,6 +9,7 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
/** /**
...@@ -18,7 +19,8 @@ public class ContentCaptureReceiverManager { ...@@ -18,7 +19,8 @@ public class ContentCaptureReceiverManager {
private static final String TAG = "ContentCapture"; private static final String TAG = "ContentCapture";
private static Boolean sDump; private static Boolean sDump;
private ContentCaptureConsumer mContentCaptureConsumer; private ArrayList<ContentCaptureConsumer> mContentCaptureConsumers =
new ArrayList<ContentCaptureConsumer>();
public static ContentCaptureReceiverManager createOrGet(WebContents webContents) { public static ContentCaptureReceiverManager createOrGet(WebContents webContents) {
return ContentCaptureReceiverManagerJni.get().createOrGet(webContents); return ContentCaptureReceiverManagerJni.get().createOrGet(webContents);
...@@ -29,22 +31,30 @@ public class ContentCaptureReceiverManager { ...@@ -29,22 +31,30 @@ public class ContentCaptureReceiverManager {
if (sDump == null) sDump = ContentCaptureFeatures.isDumpForTestingEnabled(); if (sDump == null) sDump = ContentCaptureFeatures.isDumpForTestingEnabled();
} }
public void setContentCaptureConsumer(ContentCaptureConsumer consumer) { public void addContentCaptureConsumer(ContentCaptureConsumer consumer) {
mContentCaptureConsumer = consumer; mContentCaptureConsumers.add(consumer);
} }
@CalledByNative @CalledByNative
private void didCaptureContent(Object[] session, ContentCaptureData data) { private void didCaptureContent(Object[] session, ContentCaptureData data) {
if (mContentCaptureConsumer != null) { FrameSession frameSession = toFrameSession(session);
mContentCaptureConsumer.onContentCaptured(toFrameSession(session), data); String[] urls = buildUrls(frameSession, data);
for (ContentCaptureConsumer consumer : mContentCaptureConsumers) {
if (consumer.shouldCapture(urls)) {
consumer.onContentCaptured(frameSession, data);
}
} }
if (sDump.booleanValue()) Log.i(TAG, "Captured Content: %s", data); if (sDump.booleanValue()) Log.i(TAG, "Captured Content: %s", data);
} }
@CalledByNative @CalledByNative
private void didUpdateContent(Object[] session, ContentCaptureData data) { private void didUpdateContent(Object[] session, ContentCaptureData data) {
if (mContentCaptureConsumer != null) { FrameSession frameSession = toFrameSession(session);
mContentCaptureConsumer.onContentUpdated(toFrameSession(session), data); String[] urls = buildUrls(frameSession, data);
for (ContentCaptureConsumer consumer : mContentCaptureConsumers) {
if (consumer.shouldCapture(urls)) {
consumer.onContentUpdated(frameSession, data);
}
} }
if (sDump.booleanValue()) Log.i(TAG, "Updated Content: %s", data); if (sDump.booleanValue()) Log.i(TAG, "Updated Content: %s", data);
} }
...@@ -52,8 +62,11 @@ public class ContentCaptureReceiverManager { ...@@ -52,8 +62,11 @@ public class ContentCaptureReceiverManager {
@CalledByNative @CalledByNative
private void didRemoveContent(Object[] session, long[] data) { private void didRemoveContent(Object[] session, long[] data) {
FrameSession frameSession = toFrameSession(session); FrameSession frameSession = toFrameSession(session);
if (mContentCaptureConsumer != null) { String[] urls = buildUrls(frameSession, null);
mContentCaptureConsumer.onContentRemoved(frameSession, data); for (ContentCaptureConsumer consumer : mContentCaptureConsumers) {
if (consumer.shouldCapture(urls)) {
consumer.onContentRemoved(frameSession, data);
}
} }
if (sDump.booleanValue()) { if (sDump.booleanValue()) {
Log.i(TAG, "Removed Content: %s", frameSession.get(0) + " " + Arrays.toString(data)); Log.i(TAG, "Removed Content: %s", frameSession.get(0) + " " + Arrays.toString(data));
...@@ -63,7 +76,12 @@ public class ContentCaptureReceiverManager { ...@@ -63,7 +76,12 @@ public class ContentCaptureReceiverManager {
@CalledByNative @CalledByNative
private void didRemoveSession(Object[] session) { private void didRemoveSession(Object[] session) {
FrameSession frameSession = toFrameSession(session); FrameSession frameSession = toFrameSession(session);
if (mContentCaptureConsumer != null) mContentCaptureConsumer.onSessionRemoved(frameSession); String[] urls = buildUrls(frameSession, null);
for (ContentCaptureConsumer consumer : mContentCaptureConsumers) {
if (consumer.shouldCapture(urls)) {
consumer.onSessionRemoved(frameSession);
}
}
if (sDump.booleanValue()) Log.i(TAG, "Removed Session: %s", frameSession.get(0)); if (sDump.booleanValue()) Log.i(TAG, "Removed Session: %s", frameSession.get(0));
} }
...@@ -73,6 +91,19 @@ public class ContentCaptureReceiverManager { ...@@ -73,6 +91,19 @@ public class ContentCaptureReceiverManager {
return frameSession; return frameSession;
} }
private String[] buildUrls(FrameSession session, ContentCaptureData data) {
ArrayList<String> urls = new ArrayList<String>();
if (session != null) {
for (ContentCaptureData d : session) {
urls.add(d.getValue());
}
}
if (data != null) urls.add(data.getValue());
String[] result = new String[urls.size()];
urls.toArray(result);
return result;
}
@NativeMethods @NativeMethods
interface Natives { interface Natives {
ContentCaptureReceiverManager createOrGet(WebContents webContents); ContentCaptureReceiverManager createOrGet(WebContents webContents);
......
// Copyright 2020 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.components.content_capture;
import org.chromium.base.Log;
import org.chromium.content_public.browser.WebContents;
/**
* This class is used to trigger ContentCapture unconditionally for the experiment. It doesn't
* consume any content, but is necessary to keep capturing content.
*/
public class ExperimentContentCaptureConsumer extends ContentCaptureConsumer {
private static final String TAG = "ContentCapture";
private static boolean sDump;
public static ContentCaptureConsumer create(WebContents webContents) {
if (ContentCaptureFeatures.shouldTriggerContentCaptureForExperiment()) {
return new ExperimentContentCaptureConsumer(webContents);
}
return null;
}
private ExperimentContentCaptureConsumer(WebContents webContents) {
super(webContents);
}
@Override
public void onContentCaptured(FrameSession parentFrame, ContentCaptureData contentCaptureData) {
if (sDump) Log.d(TAG, "onContentCaptured " + contentCaptureData.toString());
}
@Override
public void onSessionRemoved(FrameSession session) {
if (sDump) Log.d(TAG, "onSessionRemoved");
}
@Override
public void onContentRemoved(FrameSession session, long[] removedIds) {
if (sDump) Log.d(TAG, "onContentRemoved");
}
@Override
public void onContentUpdated(FrameSession parentFrame, ContentCaptureData contentCaptureData) {
if (sDump) Log.d(TAG, "onContentUpdated");
}
}
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "components/content_capture/common/content_capture_features.h" #include "components/content_capture/common/content_capture_features.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h" #include "base/metrics/field_trial_params.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -13,15 +14,25 @@ namespace features { ...@@ -13,15 +14,25 @@ namespace features {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
const base::Feature kContentCapture{"ContentCapture", const base::Feature kContentCapture{"ContentCapture",
base::FEATURE_ENABLED_BY_DEFAULT}; base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kContentCaptureTriggeringForExperiment{
"ContentCaptureTriggeringForExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
#else #else
const base::Feature kContentCapture{"ContentCapture", const base::Feature kContentCapture{"ContentCapture",
base::FEATURE_DISABLED_BY_DEFAULT}; base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kContentCaptureTriggeringForExperiment{
"ContentCaptureTriggeringForExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
#endif #endif
bool IsContentCaptureEnabled() { bool IsContentCaptureEnabled() {
return base::FeatureList::IsEnabled(kContentCapture); return base::FeatureList::IsEnabled(kContentCapture);
} }
bool ShouldTriggerContentCaptureForExperiment() {
return base::FeatureList::IsEnabled(kContentCaptureTriggeringForExperiment);
}
int TaskLongDelayInMilliseconds() { int TaskLongDelayInMilliseconds() {
return base::GetFieldTrialParamByFeatureAsInt( return base::GetFieldTrialParamByFeatureAsInt(
kContentCapture, "task_long_delay_in_milliseconds", 5000); kContentCapture, "task_long_delay_in_milliseconds", 5000);
......
...@@ -13,7 +13,13 @@ namespace features { ...@@ -13,7 +13,13 @@ namespace features {
extern const base::Feature kContentCaptureEnabled; extern const base::Feature kContentCaptureEnabled;
// ContentCapture is triggered in the unpredictable conditions which might be
// changed on different aiai release or configuration push, this feature allows
// us to trigger the ContentCapture independently to get the unbiased result.
extern const base::Feature kContentCaptureTriggeringForExperiment;
bool IsContentCaptureEnabled(); bool IsContentCaptureEnabled();
bool ShouldTriggerContentCaptureForExperiment();
int TaskLongDelayInMilliseconds(); int TaskLongDelayInMilliseconds();
int TaskShortDelayInMilliseconds(); int TaskShortDelayInMilliseconds();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment