| /* |
| * 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.os.CancellationSignal; |
| import android.webkit.WebView; |
| |
| import java.util.function.Consumer; |
| |
| /** |
| * ScrollCapture for WebView. |
| */ |
| public 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 void onScrollRequested(@NonNull WebView view, @NonNull Rect scrollBounds, |
| @NonNull Rect requestRect, CancellationSignal cancellationSignal, |
| Consumer<ScrollResult> resultConsumer) { |
| |
| 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()) { |
| resultConsumer.accept(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); |
| } |
| resultConsumer.accept(result); |
| } |
| |
| @Override |
| public void onPrepareForEnd(@NonNull WebView view) { |
| view.scrollTo(mOriginScrollX, mOriginScrollY); |
| } |
| |
| } |
| |