Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9bcef368 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Enables scroll capture for WebView" into sc-v2-dev

parents d3c04e2b d1b52535
Loading
Loading
Loading
Loading
+26 −12
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.util.Log;
import android.view.ScrollCaptureCallback;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.ListView;

/**
@@ -43,7 +44,7 @@ public class ScrollCaptureInternal {
    private static final int DOWN = 1;

    /**
     * Not a ViewGroup, or cannot scroll according to View APIs.
     * Cannot scroll according to {@link View#canScrollVertically}.
     */
    public static final int TYPE_FIXED = 0;

@@ -60,7 +61,7 @@ public class ScrollCaptureInternal {
    public static final int TYPE_RECYCLING = 2;

    /**
     * The ViewGroup scrolls, but has no child views in
     * Unknown scrollable view with no child views (or not a subclass of ViewGroup).
     */
    private static final int TYPE_OPAQUE = 3;

@@ -73,16 +74,6 @@ public class ScrollCaptureInternal {
     * as excluded during scroll capture search.
     */
    private static int detectScrollingType(View view) {
        // Must be a ViewGroup
        if (!(view instanceof ViewGroup)) {
            if (DEBUG_VERBOSE) {
                Log.v(TAG, "hint: not a subclass of ViewGroup");
            }
            return TYPE_FIXED;
        }
        if (DEBUG_VERBOSE) {
            Log.v(TAG, "hint: is a subclass of ViewGroup");
        }
        // Confirm that it can scroll.
        if (!(view.canScrollVertically(DOWN) || view.canScrollVertically(UP))) {
            // Nothing to scroll here, move along.
@@ -94,6 +85,17 @@ public class ScrollCaptureInternal {
        if (DEBUG_VERBOSE) {
            Log.v(TAG, "hint: can be scrolled up or down");
        }
        // Must be a ViewGroup
        if (!(view instanceof ViewGroup)) {
            if (DEBUG_VERBOSE) {
                Log.v(TAG, "hint: not a subclass of ViewGroup");
            }
            return TYPE_OPAQUE;
        }
        if (DEBUG_VERBOSE) {
            Log.v(TAG, "hint: is a subclass of ViewGroup");
        }

        // ScrollViews accept only a single child.
        if (((ViewGroup) view).getChildCount() > 1) {
            if (DEBUG_VERBOSE) {
@@ -188,6 +190,18 @@ public class ScrollCaptureInternal {
                }
                return new ScrollCaptureViewSupport<>((ViewGroup) view,
                        new RecyclerViewCaptureHelper());
            case TYPE_OPAQUE:
                if (DEBUG) {
                    Log.d(TAG, "scroll capture: FOUND " + view.getClass().getName()
                            + "[" + resolveId(view.getContext(), view.getId()) + "]"
                            + " -> TYPE_OPAQUE");
                }
                if (view instanceof WebView) {
                    Log.d(TAG, "scroll capture: Using WebView support");
                    return new ScrollCaptureViewSupport<>((WebView) view,
                            new WebViewCaptureHelper());
                }
                break;
            case TYPE_FIXED:
                // ignore
                break;
+100 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.view;

import static android.util.MathUtils.constrain;

import static java.lang.Math.max;
import static java.lang.Math.min;

import android.annotation.NonNull;
import android.graphics.Rect;
import android.webkit.WebView;

/**
 * ScrollCapture for WebView.
 */
class WebViewCaptureHelper implements ScrollCaptureViewHelper<WebView> {
    private static final String TAG = "WebViewScrollCapture";

    private final Rect mRequestWebViewLocal = new Rect();
    private final Rect mWebViewBounds = new Rect();

    private int mOriginScrollY;
    private int mOriginScrollX;

    @Override
    public boolean onAcceptSession(@NonNull WebView view) {
        return view.isVisibleToUser()
                && (view.getContentHeight() * view.getScale()) > view.getHeight();
    }

    @Override
    public void onPrepareForStart(@NonNull WebView view, @NonNull Rect scrollBounds) {
        mOriginScrollX = view.getScrollX();
        mOriginScrollY = view.getScrollY();
    }

    @NonNull
    @Override
    public ScrollResult onScrollRequested(@NonNull WebView view, @NonNull Rect scrollBounds,
            @NonNull Rect requestRect) {

        int scrollDelta = view.getScrollY() - mOriginScrollY;

        ScrollResult result = new ScrollResult();
        result.requestedArea = new Rect(requestRect);
        result.availableArea = new Rect();
        result.scrollDelta = scrollDelta;

        mWebViewBounds.set(0, 0, view.getWidth(), view.getHeight());

        if (!view.isVisibleToUser()) {
            return result;
        }

        // Map the request into local coordinates
        mRequestWebViewLocal.set(requestRect);
        mRequestWebViewLocal.offset(0, -scrollDelta);

        // Offset to center the rect vertically, clamp to available content
        int upLimit = min(0, -view.getScrollY());
        int contentHeightPx = (int) (view.getContentHeight() * view.getScale());
        int downLimit = max(0, (contentHeightPx - view.getHeight()) - view.getScrollY());
        int scrollToCenter = mRequestWebViewLocal.centerY() - mWebViewBounds.centerY();
        int scrollMovement = constrain(scrollToCenter, upLimit, downLimit);

        // Scroll and update relative based on  the new position
        view.scrollBy(mOriginScrollX, scrollMovement);
        scrollDelta = view.getScrollY() - mOriginScrollY;
        mRequestWebViewLocal.offset(0, -scrollMovement);
        result.scrollDelta = scrollDelta;

        if (mRequestWebViewLocal.intersect(mWebViewBounds)) {
            result.availableArea = new Rect(mRequestWebViewLocal);
            result.availableArea.offset(0, result.scrollDelta);
        }
        return result;
    }

    @Override
    public void onPrepareForEnd(@NonNull WebView view) {
        view.scrollTo(mOriginScrollX, mOriginScrollY);
    }

}