Commit 2812e863 authored by Tao Bai's avatar Tao Bai Committed by Commit Bot

Reland "Upstreaming ContentCapture"

This reverts commit 5347b384.

Reason for revert: The downstream has rolled to my change, this
patch should be good to go.

Original change's description:
> Revert "Upstreaming ContentCapture"
> 
> This reverts commit edc475ed.
> 
> Reason for revert: Causes compilation failure:
> https://logs.chromium.org/logs/chrome/buildbucket/cr-buildbucket.appspot.com/8895755054118235408/+/steps/compile/0/stdout
> 
> ../../clank/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolderForQ.java:26: error: method does not override or implement a method from a supertype
>     @Override
>     ^
> 
> 
> 
> Original change's description:
> > Upstreaming ContentCapture
> > 
> > Related downstream change:
> > https://chrome-internal-review.googlesource.com/c/clank/internal/apps/+/2172237
> > 
> > Binary-Size: all added code was from downstream, the size increase is expected.
> > Bug: 951275
> > Change-Id: Ibf56135e2a7d2f437f167dc0cdb7761bce447e86
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1922603
> > Reviewed-by: Changwan Ryu <changwan@chromium.org>
> > Reviewed-by: Richard Coles <torne@chromium.org>
> > Reviewed-by: David Trainor <dtrainor@chromium.org>
> > Commit-Queue: Tao Bai <michaelbai@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#718894}
> 
> TBR=michaelbai@chromium.org,dtrainor@chromium.org,torne@chromium.org,changwan@chromium.org
> 
> Change-Id: Id904c28aa48d561ccea36942da1f507982a698dd
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: 951275
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1935578
> Reviewed-by: Yoshifumi Inoue <yosin@chromium.org>
> Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#719031}

TBR=michaelbai@chromium.org,yosin@chromium.org,dtrainor@chromium.org,torne@chromium.org,changwan@chromium.org

Change-Id: I1aeb6ccb43989d58aa872860d2048b1eff2815ee
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 951275
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1936969Reviewed-by: default avatarTao Bai <michaelbai@chromium.org>
Commit-Queue: Tao Bai <michaelbai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#719161}
parent 42c7a390
...@@ -7,21 +7,6 @@ import("//android_webview/variables.gni") ...@@ -7,21 +7,6 @@ import("//android_webview/variables.gni")
import("//build/config/android/config.gni") import("//build/config/android/config.gni")
import("//build/config/android/rules.gni") import("//build/config/android/rules.gni")
# TODO(crbug.com/951275): Clean this up once internal code is upstreamed.
android_library("webview_chromium_for_q_upstream_java") {
# Needed for android.webkit.WebViewDelegate.
alternative_android_sdk_dep =
"//third_party/android_sdk:public_framework_system_java"
deps = [
":glue",
]
java_files = [ "java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForQ.java" ]
jacoco_never_instrument = true
}
android_library("glue") { android_library("glue") {
deps = [ deps = [
"//android_webview:android_webview_java", "//android_webview:android_webview_java",
...@@ -35,6 +20,7 @@ android_library("glue") { ...@@ -35,6 +20,7 @@ android_library("glue") {
"//base:jni_java", "//base:jni_java",
"//components/autofill/android:autofill_java", "//components/autofill/android:autofill_java",
"//components/autofill/android:provider_java", "//components/autofill/android:provider_java",
"//components/content_capture/android:java",
"//components/embedder_support/android:application_java", "//components/embedder_support/android:application_java",
"//content/public/android:content_java", "//content/public/android:content_java",
"//net/android:net_java", "//net/android:net_java",
...@@ -83,6 +69,7 @@ android_library("glue") { ...@@ -83,6 +69,7 @@ android_library("glue") {
"java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForO.java", "java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForO.java",
"java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForOMR1.java", "java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForOMR1.java",
"java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForP.java", "java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForP.java",
"java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForQ.java",
"java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java", "java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java",
"java/src/com/android/webview/chromium/WebViewDatabaseAdapter.java", "java/src/com/android/webview/chromium/WebViewDatabaseAdapter.java",
"java/src/com/android/webview/chromium/WebViewDelegateFactory.java", "java/src/com/android/webview/chromium/WebViewDelegateFactory.java",
......
...@@ -72,6 +72,8 @@ import org.chromium.base.metrics.CachedMetrics.TimesHistogramSample; ...@@ -72,6 +72,8 @@ import org.chromium.base.metrics.CachedMetrics.TimesHistogramSample;
import org.chromium.base.metrics.ScopedSysTraceEvent; import org.chromium.base.metrics.ScopedSysTraceEvent;
import org.chromium.base.task.PostTask; import org.chromium.base.task.PostTask;
import org.chromium.components.autofill.AutofillProvider; import org.chromium.components.autofill.AutofillProvider;
import org.chromium.components.content_capture.ContentCaptureConsumerImpl;
import org.chromium.components.content_capture.ContentCaptureFeatures;
import org.chromium.components.embedder_support.application.ClassLoaderContextWrapperFactory; import org.chromium.components.embedder_support.application.ClassLoaderContextWrapperFactory;
import org.chromium.content_public.browser.NavigationHistory; import org.chromium.content_public.browser.NavigationHistory;
import org.chromium.content_public.browser.SmartClipProvider; import org.chromium.content_public.browser.SmartClipProvider;
...@@ -1883,6 +1885,16 @@ class WebViewChromium implements WebViewProvider, WebViewProvider.ScrollDelegate ...@@ -1883,6 +1885,16 @@ class WebViewChromium implements WebViewProvider, WebViewProvider.ScrollDelegate
mAwContents.onProvideAutoFillVirtualStructure(structure, flags); mAwContents.onProvideAutoFillVirtualStructure(structure, flags);
} }
@Override
public void onProvideContentCaptureStructure(ViewStructure structure, int flags) {
if (ContentCaptureFeatures.isDumpForTestingEnabled()) {
Log.i("ContentCapture", "onProvideContentCaptureStructure");
}
mAwContents.setContentCaptureConsumer(ContentCaptureConsumerImpl.create(
ClassLoaderContextWrapperFactory.get(mWebView.getContext()), mWebView, structure,
mAwContents.getWebContents()));
}
// WebViewProvider glue methods --------------------------------------------------------------- // WebViewProvider glue methods ---------------------------------------------------------------
@Override @Override
......
...@@ -18,10 +18,6 @@ trichrome_webview_64_32_android_manifest = "$root_gen_dir/android_webview/trichr ...@@ -18,10 +18,6 @@ trichrome_webview_64_32_android_manifest = "$root_gen_dir/android_webview/trichr
upstream_only_webview_deps = [ upstream_only_webview_deps = [
"//android_webview:platform_service_bridge_upstream_implementation_java", "//android_webview:platform_service_bridge_upstream_implementation_java",
"//android_webview/nonembedded:icon_resources", "//android_webview/nonembedded:icon_resources",
# TODO(crbug.com/951275): Clean this up once relevant internal code
# is upstreamed.
"//android_webview/glue:webview_chromium_for_q_upstream_java",
] ]
if (webview_includes_weblayer) { if (webview_includes_weblayer) {
......
...@@ -1767,10 +1767,6 @@ template("monochrome_public_apk_or_module_tmpl") { ...@@ -1767,10 +1767,6 @@ template("monochrome_public_apk_or_module_tmpl") {
deps += [ deps += [
":monochrome_java", ":monochrome_java",
"//android_webview:platform_service_bridge_upstream_implementation_java", "//android_webview:platform_service_bridge_upstream_implementation_java",
# TODO(crbug.com/951275): Clean this up once relevant internal code
# is upstreamed.
"//android_webview/glue:webview_chromium_for_q_upstream_java",
] ]
if (webview_includes_weblayer) { if (webview_includes_weblayer) {
deps += [ "//weblayer/browser/java:gms_bridge_upstream_impl_java" ] deps += [ "//weblayer/browser/java:gms_bridge_upstream_impl_java" ]
......
...@@ -57,6 +57,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector; ...@@ -57,6 +57,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.toolbar.ControlContainer; import org.chromium.chrome.browser.toolbar.ControlContainer;
import org.chromium.chrome.browser.toolbar.ToolbarColors; import org.chromium.chrome.browser.toolbar.ToolbarColors;
import org.chromium.components.content_capture.ContentCaptureConsumer; import org.chromium.components.content_capture.ContentCaptureConsumer;
import org.chromium.components.content_capture.ContentCaptureConsumerImpl;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.KeyboardVisibilityDelegate; import org.chromium.ui.KeyboardVisibilityDelegate;
import org.chromium.ui.UiUtils; import org.chromium.ui.UiUtils;
...@@ -1141,24 +1142,18 @@ public class CompositorViewHolder extends FrameLayout ...@@ -1141,24 +1142,18 @@ public class CompositorViewHolder extends FrameLayout
if (mTabVisible != null) initializeTab(mTabVisible); if (mTabVisible != null) initializeTab(mTabVisible);
if (mShouldCreateContentCaptureConsumer) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mContentCaptureConsumer = createContentCaptureConsumer(); if (mShouldCreateContentCaptureConsumer) {
mShouldCreateContentCaptureConsumer = false; mContentCaptureConsumer =
ContentCaptureConsumerImpl.create(getContext(), this, getWebContents());
mShouldCreateContentCaptureConsumer = false;
}
} }
if (mContentCaptureConsumer != null) { if (mContentCaptureConsumer != null) {
mContentCaptureConsumer.onWebContentsChanged(getWebContents()); mContentCaptureConsumer.onWebContentsChanged(getWebContents());
} }
} }
/**
* This method is used by subclass to provide ContentCaptureConsumer.
*
* @return the ContentCaptureConsumer or null if it is not available.
*/
protected ContentCaptureConsumer createContentCaptureConsumer() {
return null;
}
/** /**
* Sets the correct size for {@link View} on {@code tab} and sets the correct rendering * Sets the correct size for {@link View} on {@code tab} and sets the correct rendering
* parameters on {@link WebContents} on {@code tab}. * parameters on {@link WebContents} on {@code tab}.
......
...@@ -28,11 +28,20 @@ android_library("java") { ...@@ -28,11 +28,20 @@ android_library("java") {
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
java_files = [ java_files = [
"java/src/org/chromium/components/content_capture/ContentCaptureConsumer.java", "java/src/org/chromium/components/content_capture/ContentCaptureConsumer.java",
"java/src/org/chromium/components/content_capture/ContentCaptureConsumerImpl.java",
"java/src/org/chromium/components/content_capture/ContentCaptureController.java", "java/src/org/chromium/components/content_capture/ContentCaptureController.java",
"java/src/org/chromium/components/content_capture/ContentCaptureControllerImpl.java",
"java/src/org/chromium/components/content_capture/ContentCaptureData.java", "java/src/org/chromium/components/content_capture/ContentCaptureData.java",
"java/src/org/chromium/components/content_capture/ContentCaptureFeatures.java", "java/src/org/chromium/components/content_capture/ContentCaptureFeatures.java",
"java/src/org/chromium/components/content_capture/ContentCaptureReceiverManager.java", "java/src/org/chromium/components/content_capture/ContentCaptureReceiverManager.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/ContentUpdateTask.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/PlatformSession.java",
"java/src/org/chromium/components/content_capture/ProcessContentCaptureDataTask.java",
"java/src/org/chromium/components/content_capture/SessionRemovedTask.java",
] ]
} }
......
// Copyright 2019 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 android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.view.View;
import android.view.ViewStructure;
import org.chromium.base.annotations.VerifiesOnQ;
import org.chromium.base.task.AsyncTask;
import org.chromium.content_public.browser.WebContents;
/**
* This class receive captured content and send it to framework in non-UI
* thread.
*/
@VerifiesOnQ
@TargetApi(Build.VERSION_CODES.Q)
public class ContentCaptureConsumerImpl extends ContentCaptureConsumer {
private PlatformSession mPlatformSession;
private final View mView;
/**
* This method is used when ViewStructure is available.
*
* @Return ContentCaptureConsumer or null if ContentCapture service isn't
* available, disabled or isn't AiAi service.
*/
public static ContentCaptureConsumer create(
Context context, View view, ViewStructure structure, WebContents webContents) {
if (ContentCaptureController.getInstance() == null) {
ContentCaptureControllerImpl.init(context.getApplicationContext());
}
if (!ContentCaptureController.getInstance().shouldStartCapture()) return null;
return new ContentCaptureConsumerImpl(view, structure, webContents);
}
/**
* This method is used when ViewStructure isn't available and needs to be
* created.
*/
public static ContentCaptureConsumer create(
Context context, View view, WebContents webContents) {
return create(context, view, null, webContents);
}
private ContentCaptureConsumerImpl(
View view, ViewStructure viewStructure, WebContents webContents) {
super(webContents);
mView = view;
if (viewStructure != null) {
mPlatformSession = new PlatformSession(
view.getContentCaptureSession(), viewStructure.getAutofillId());
}
}
@Override
public void onContentCaptured(FrameSession parentFrame, ContentCaptureData contentCaptureData) {
if (mPlatformSession == null) {
mPlatformSession = PlatformSession.fromView(mView);
if (mPlatformSession == null) return;
}
new ContentCapturedTask(parentFrame, contentCaptureData, mPlatformSession)
.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
@Override
public void onContentUpdated(FrameSession parentFrame, ContentCaptureData contentCaptureData) {
if (mPlatformSession == null) return;
new ContentUpdateTask(parentFrame, contentCaptureData, mPlatformSession)
.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
@Override
public void onSessionRemoved(FrameSession frame) {
if (frame.isEmpty() || mPlatformSession == null) return;
new SessionRemovedTask(frame, mPlatformSession)
.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
@Override
public void onContentRemoved(FrameSession frame, long[] removedIds) {
if (frame.isEmpty() || mPlatformSession == null) return;
new ContentRemovedTask(frame, removedIds, mPlatformSession)
.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
}
// Copyright 2019 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 android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.LocusId;
import android.os.Build;
import android.view.contentcapture.ContentCaptureCondition;
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.DataRemovalRequest;
import org.chromium.base.BuildInfo;
import org.chromium.base.Log;
import org.chromium.base.annotations.VerifiesOnQ;
import java.util.Set;
/**
* The implementation of ContentCaptureController to verify ContentCaptureService
* is Aiai and signed by right certificate, this class also read whitelist from
* framework and set to native side.
*/
// TODO(crbug.com/965566): Write junit tests for this when junit supports q.
@VerifiesOnQ
@TargetApi(Build.VERSION_CODES.Q)
public class ContentCaptureControllerImpl extends ContentCaptureController {
private static final String TAG = "ContentCapture";
private static final String AIAI_PACKAGE_NAME = "com.google.android.as";
private boolean mShouldStartCapture;
private ContentCaptureManager mContentCaptureManager;
public static void init(Context context) {
sContentCaptureController = new ContentCaptureControllerImpl(context);
}
public ContentCaptureControllerImpl(Context context) {
mContentCaptureManager = context.getSystemService(ContentCaptureManager.class);
verifyService();
}
@Override
public boolean shouldStartCapture() {
return mShouldStartCapture;
}
private void verifyService() {
if (mContentCaptureManager == null) {
log("ContentCaptureManager isn't available.");
return;
}
ComponentName componentName = mContentCaptureManager.getServiceComponentName();
if (componentName == null) {
log("Service isn't available.");
return;
}
mShouldStartCapture = AIAI_PACKAGE_NAME.equals(componentName.getPackageName());
if (!mShouldStartCapture) {
log("Package doesn't match, current one is "
+ mContentCaptureManager.getServiceComponentName().getPackageName());
// Disable the ContentCapture if there is no testing flag.
if (!BuildInfo.isDebugAndroid() && !ContentCaptureFeatures.isDumpForTestingEnabled()) {
return;
}
}
mShouldStartCapture = mContentCaptureManager.isContentCaptureEnabled();
if (!mShouldStartCapture) {
log("ContentCapture disabled.");
}
}
@Override
protected void pullWhitelist() {
Set<ContentCaptureCondition> conditions =
mContentCaptureManager.getContentCaptureConditions();
String[] whiteList = null;
boolean[] isRegEx = null;
if (conditions != null) {
whiteList = new String[conditions.size()];
isRegEx = new boolean[conditions.size()];
int index = 0;
for (ContentCaptureCondition c : conditions) {
whiteList[index] = c.getLocusId().getId();
isRegEx[index] = (c.getFlags() & ContentCaptureCondition.FLAG_IS_REGEX) != 0;
index++;
}
}
setWhitelist(whiteList, isRegEx);
}
private void log(String msg) {
if (!ContentCaptureFeatures.isDumpForTestingEnabled()) return;
Log.i(TAG, msg);
}
@Override
public void clearAllContentCaptureData() {
if (mContentCaptureManager == null) return;
mContentCaptureManager.removeData(new DataRemovalRequest.Builder().forEverything().build());
}
@Override
public void clearContentCaptureDataForURLs(String[] urlsToDelete) {
if (mContentCaptureManager == null) return;
DataRemovalRequest.Builder builder = new DataRemovalRequest.Builder();
for (String url : urlsToDelete) {
builder = builder.addLocusId(
new LocusId(url), /* Signals that we aren't using extra flags */ 0);
}
mContentCaptureManager.removeData(builder.build());
}
}
// Copyright 2019 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 android.view.autofill.AutofillId;
import org.chromium.components.content_capture.PlatformSession.PlatformSessionData;
/**
* The task to notify platform of the captured content
*/
class ContentCapturedTask extends ProcessContentCaptureDataTask {
public ContentCapturedTask(FrameSession session, ContentCaptureData contentCaptureData,
PlatformSession platformSession) {
super(session, contentCaptureData, platformSession);
}
@Override
protected AutofillId notifyPlatform(
PlatformSessionData parentPlatformSessionData, ContentCaptureData data) {
return notifyViewAppeared(parentPlatformSessionData, data);
}
}
// Copyright 2019 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.components.content_capture.PlatformSession.PlatformSessionData;
/**
* The task to remove the captured content from the platform.
*/
class ContentRemovedTask extends NotificationTask {
private final long[] mRemovedIds;
public ContentRemovedTask(
FrameSession session, long[] removedIds, PlatformSession platformSession) {
super(session, platformSession);
mRemovedIds = removedIds;
}
@Override
protected Boolean doInBackground() {
removeContent();
return true;
}
private void removeContent() {
log("ContentRemovedTask.removeContent");
PlatformSessionData platformSessionData = buildCurrentSession();
if (platformSessionData == null) return;
platformSessionData.contentCaptureSession.notifyViewsDisappeared(
mPlatformSession.getRootPlatformSessionData().autofillId, mRemovedIds);
}
}
// Copyright 2019 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 android.view.autofill.AutofillId;
import org.chromium.components.content_capture.PlatformSession.PlatformSessionData;
/**
* The task to update the captured content in platform.
*/
class ContentUpdateTask extends ProcessContentCaptureDataTask {
public ContentUpdateTask(FrameSession session, ContentCaptureData contentCaptureData,
PlatformSession platformSession) {
super(session, contentCaptureData, platformSession);
}
@Override
protected AutofillId notifyPlatform(
PlatformSessionData parentPlatformSessionData, ContentCaptureData data) {
return notifyViewTextChanged(parentPlatformSessionData, data);
}
private AutofillId notifyViewTextChanged(
PlatformSessionData parentPlatformSessionData, ContentCaptureData data) {
AutofillId autofillId = parentPlatformSessionData.contentCaptureSession.newAutofillId(
mPlatformSession.getRootPlatformSessionData().autofillId, data.getId());
parentPlatformSessionData.contentCaptureSession.notifyViewTextChanged(
autofillId, data.getValue());
return autofillId;
}
}
// Copyright 2019 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 android.annotation.TargetApi;
import android.content.LocusId;
import android.graphics.Rect;
import android.os.Build;
import android.text.TextUtils;
import android.view.ViewStructure;
import android.view.autofill.AutofillId;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureSession;
import org.chromium.base.Log;
import org.chromium.base.annotations.VerifiesOnQ;
import org.chromium.base.task.AsyncTask;
import org.chromium.components.content_capture.PlatformSession.PlatformSessionData;
/**
* The background task to talk to the ContentCapture Service.
*/
@VerifiesOnQ
@TargetApi(Build.VERSION_CODES.Q)
abstract class NotificationTask extends AsyncTask<Boolean> {
private static final String TAG = "ContentCapture";
private static Boolean sDump;
protected final FrameSession mSession;
protected final PlatformSession mPlatformSession;
public NotificationTask(FrameSession session, PlatformSession platformSession) {
mSession = session;
mPlatformSession = platformSession;
if (sDump == null) sDump = ContentCaptureFeatures.isDumpForTestingEnabled();
}
// Build up FrameIdToPlatformSessionData map of mSession, and return the current
// session the task should run against.
public PlatformSessionData buildCurrentSession() {
if (mSession == null || mSession.isEmpty()) {
return mPlatformSession.getRootPlatformSessionData();
}
// Build the session from root.
PlatformSessionData platformSessionData = mPlatformSession.getRootPlatformSessionData();
for (int i = mSession.size() - 1; i >= 0; i--) {
platformSessionData = createOrGetSession(platformSessionData, mSession.get(i));
if (platformSessionData == null) break;
}
return platformSessionData;
}
protected AutofillId notifyViewAppeared(
PlatformSessionData parentPlatformSessionData, ContentCaptureData data) {
ViewStructure viewStructure =
parentPlatformSessionData.contentCaptureSession.newVirtualViewStructure(
parentPlatformSessionData.autofillId, data.getId());
if (!data.hasChildren()) viewStructure.setText(data.getValue());
Rect rect = data.getBounds();
// Always set scroll as (0, 0).
viewStructure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height());
parentPlatformSessionData.contentCaptureSession.notifyViewAppeared(viewStructure);
return viewStructure.getAutofillId();
}
public PlatformSessionData createOrGetSession(
PlatformSessionData parentPlatformSessionData, ContentCaptureData frame) {
PlatformSessionData platformSessionData =
mPlatformSession.getFrameIdToPlatformSessionData().get(frame.getId());
if (platformSessionData == null && !TextUtils.isEmpty(frame.getValue())) {
ContentCaptureSession session =
parentPlatformSessionData.contentCaptureSession.createContentCaptureSession(
new ContentCaptureContext.Builder(new LocusId(frame.getValue()))
.build());
AutofillId autofillId = parentPlatformSessionData.contentCaptureSession.newAutofillId(
mPlatformSession.getRootPlatformSessionData().autofillId, frame.getId());
autofillId = notifyViewAppeared(parentPlatformSessionData, frame);
platformSessionData = new PlatformSessionData(session, autofillId);
mPlatformSession.getFrameIdToPlatformSessionData().put(
frame.getId(), platformSessionData);
}
return platformSessionData;
}
protected void log(String message) {
if (sDump.booleanValue()) Log.i(TAG, message);
}
@Override
protected void onPostExecute(Boolean result) {}
}
// Copyright 2019 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 android.annotation.TargetApi;
import android.os.Build;
import android.view.View;
import android.view.ViewStructure;
import android.view.autofill.AutofillId;
import android.view.contentcapture.ContentCaptureSession;
import android.widget.Checkable;
import org.chromium.base.annotations.VerifiesOnQ;
import java.util.HashMap;
/**
* The class to manage the platform session.
*/
@VerifiesOnQ
@TargetApi(Build.VERSION_CODES.Q)
class PlatformSession {
/**
* PlatformSessionData wraps the ContentCaptureSession and its corresponding
* AutofillId. The AutofillId should be consistent with Android Autofill's
* AutofillId, so the service can use content capture as the heuristic for
* autofill.
*/
public static final class PlatformSessionData {
public final ContentCaptureSession contentCaptureSession;
public final AutofillId autofillId;
public PlatformSessionData(ContentCaptureSession session, AutofillId id) {
contentCaptureSession = session;
autofillId = id;
}
}
private PlatformSessionData mRootPlatformSessionData;
private HashMap<Long, PlatformSessionData> mFrameIdToPlatformSessionData;
public static PlatformSession fromView(View view) {
ContentCaptureSession session = view.getContentCaptureSession();
if (session == null) return null;
ViewStructure structure = session.newViewStructure(view);
AutofillId autofillId = structure.getAutofillId();
if (autofillId == null) return null;
// Simulate the logical in View.onProvideStructure()
structure.setDimens(view.getLeft(), view.getTop(), 0, 0, view.getRight() - view.getLeft(),
view.getBottom() - view.getTop());
structure.setVisibility(view.getVisibility());
structure.setEnabled(view.isEnabled());
structure.setClickable(view.isClickable());
structure.setFocusable(view.isFocusable());
structure.setFocused(view.isFocused());
structure.setAccessibilityFocused(view.isAccessibilityFocused());
structure.setSelected(view.isSelected());
structure.setActivated(view.isActivated());
structure.setLongClickable(view.isLongClickable());
if (view instanceof Checkable) {
structure.setCheckable(true);
if (((Checkable) view).isChecked()) structure.setChecked(true);
}
if (view.isOpaque()) structure.setOpaque(true);
if (view.isContextClickable()) structure.setContextClickable(true);
CharSequence className = view.getAccessibilityClassName();
if (className != null) structure.setClassName(className.toString());
structure.setContentDescription(view.getContentDescription());
return new PlatformSession(session, autofillId);
}
public PlatformSession(ContentCaptureSession session, AutofillId id) {
mRootPlatformSessionData = new PlatformSessionData(session, id);
}
public HashMap<Long, PlatformSessionData> getFrameIdToPlatformSessionData() {
if (mFrameIdToPlatformSessionData == null) {
mFrameIdToPlatformSessionData = new HashMap<Long, PlatformSessionData>();
}
return mFrameIdToPlatformSessionData;
}
public PlatformSessionData getRootPlatformSessionData() {
return mRootPlatformSessionData;
}
}
// Copyright 2019 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 android.view.autofill.AutofillId;
import org.chromium.components.content_capture.PlatformSession.PlatformSessionData;
import java.util.List;
/**
* The base class to process the ContentCaptureData.
*/
abstract class ProcessContentCaptureDataTask extends NotificationTask {
private final ContentCaptureData mContentCaptureData;
/**
* @param session
* @param contentCaptureData
* @param platformSession
*/
public ProcessContentCaptureDataTask(FrameSession session,
ContentCaptureData contentCaptureData, PlatformSession platformSession) {
super(session, platformSession);
mContentCaptureData = contentCaptureData;
}
@Override
protected Boolean doInBackground() {
processContent();
return true;
}
private void processContent() {
log("ProcessContentTaskBase.processContent");
PlatformSessionData platformSessionData = buildCurrentSession();
if (platformSessionData == null) return;
processCaptureData(platformSessionData, mContentCaptureData);
}
private boolean processCaptureData(
PlatformSessionData parentPlatformSessionData, ContentCaptureData data) {
if (data == null) return false;
if (data.hasChildren()) {
PlatformSessionData platformSessionData;
if (data.getValue() != null) {
// This is frame.
platformSessionData = createOrGetSession(parentPlatformSessionData, data);
if (platformSessionData == null) return false;
} else {
// This is scrollable area.
AutofillId autofillId = notifyPlatform(parentPlatformSessionData, data);
// To add children below scrollable area in frame, the ContentCaptureSession
// of the scrollable area is the frame the scrollable area belong to, AutofillId
// is scrollable area's AutofillId.
if (autofillId == null) return false;
platformSessionData = new PlatformSessionData(
parentPlatformSessionData.contentCaptureSession, autofillId);
}
List<ContentCaptureData> children = data.getChildren();
for (ContentCaptureData child : children) {
if (!processCaptureData(platformSessionData, child)) return false;
}
return true;
} else {
// This is text.
return null != notifyPlatform(parentPlatformSessionData, data);
}
}
protected abstract AutofillId notifyPlatform(
PlatformSessionData parentPlatformSessionData, ContentCaptureData data);
}
// Copyright 2019 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.components.content_capture.PlatformSession.PlatformSessionData;
/**
* The task to remove the platform session
*/
class SessionRemovedTask extends NotificationTask {
public SessionRemovedTask(FrameSession session, PlatformSession platformSession) {
super(session, platformSession);
}
@Override
protected Boolean doInBackground() {
removeSession();
return true;
}
private void removeSession() {
log("SessionRemovedTask.removeSession");
PlatformSessionData removedPlatformSessionData =
mPlatformSession.getFrameIdToPlatformSessionData().remove(mSession.get(0).getId());
if (removedPlatformSessionData == null) return;
removedPlatformSessionData.contentCaptureSession.destroy();
PlatformSessionData parentPlatformSessionData =
mPlatformSession.getRootPlatformSessionData();
// We need to notify the view disappeared through the removed session's parent,
// if there are more than one session in mSession, the removed session is child
// frame, otherwise, is main frame.
if (mSession.size() > 2) {
parentPlatformSessionData =
mPlatformSession.getFrameIdToPlatformSessionData().get(mSession.get(1).getId());
}
if (parentPlatformSessionData == null) return;
parentPlatformSessionData.contentCaptureSession.notifyViewDisappeared(
removedPlatformSessionData.autofillId);
}
}
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