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

Commit 89747fc2 authored by Matt Casey's avatar Matt Casey Committed by Automerger Merge Worker
Browse files

Merge changes Ie275f5c3,I1cab53a6 into sc-dev am: 21c4c71b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14213766

Change-Id: I5a618fcd3a1df2cb2207b4c0b4e0f17c7beb5401
parents 5f800005 21c4c71b
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -105,6 +105,14 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr
        int prevAnchorTop = anchor.getTop();
        // Note: requestChildRectangleOnScreen may modify rectangle, must pass pass in a copy here
        Rect input = new Rect(requestedContentBounds);
        // Expand input rect to get the requested rect to be in the center
        int remainingHeight = recyclerView.getHeight() - recyclerView.getPaddingTop()
                - recyclerView.getPaddingBottom() - input.height();
        if (remainingHeight > 0) {
            input.inset(0, -remainingHeight / 2);
        }
        Log.d(TAG, "input (post center adjustment) = " + input);

        if (recyclerView.requestChildRectangleOnScreen(anchor, input, true)) {
            int scrolled = prevAnchorTop - anchor.getTop(); // inverse of movement
            Log.d(TAG, "RecyclerView scrolled by " + scrolled + " px");
+9 −4
Original line number Diff line number Diff line
@@ -145,7 +145,9 @@ public class RecyclerViewCaptureHelperTest {
        ScrollResult scrollResult = rvc.onScrollRequested(mTarget, scrollBounds, request);
        assertThat(request).isEqualTo(scrollResult.requestedArea);
        assertThat(request).isEqualTo(scrollResult.availableArea);
        assertThat(scrollResult.scrollDelta).isEqualTo(CAPTURE_HEIGHT);
        // Capture height centered in the window
        assertThat(scrollResult.scrollDelta).isEqualTo(
                CAPTURE_HEIGHT + (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
    }

@@ -163,7 +165,8 @@ public class RecyclerViewCaptureHelperTest {
        ScrollResult scrollResult = helper.onScrollRequested(mTarget, scrollBounds, request);
        assertThat(request).isEqualTo(scrollResult.requestedArea);
        assertThat(request).isEqualTo(scrollResult.availableArea);
        assertThat(scrollResult.scrollDelta).isEqualTo(-CAPTURE_HEIGHT);
        assertThat(scrollResult.scrollDelta).isEqualTo(
                -CAPTURE_HEIGHT - (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
    }

@@ -182,7 +185,8 @@ public class RecyclerViewCaptureHelperTest {
        ScrollResult scrollResult = helper.onScrollRequested(mTarget, scrollBounds, request);
        assertThat(request).isEqualTo(scrollResult.requestedArea);
        assertThat(request).isEqualTo(scrollResult.availableArea);
        assertThat(scrollResult.scrollDelta).isEqualTo(CAPTURE_HEIGHT);
        assertThat(scrollResult.scrollDelta).isEqualTo(
                CAPTURE_HEIGHT + (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
    }

@@ -200,7 +204,8 @@ public class RecyclerViewCaptureHelperTest {
        ScrollResult scrollResult = helper.onScrollRequested(mTarget, scrollBounds, request);
        assertThat(request).isEqualTo(scrollResult.requestedArea);
        assertThat(request).isEqualTo(scrollResult.availableArea);
        assertThat(scrollResult.scrollDelta).isEqualTo(-CAPTURE_HEIGHT);
        assertThat(scrollResult.scrollDelta).isEqualTo(
                -CAPTURE_HEIGHT - (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
    }

+13 −44
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.systemui.screenshot;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.HardwareRenderer;
@@ -32,7 +31,6 @@ import android.os.Bundle;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.IWindowManager;
import android.view.ScrollCaptureResponse;
import android.view.View;
import android.widget.ImageView;
@@ -65,14 +63,10 @@ public class LongScreenshotActivity extends Activity {
    private static final String KEY_SAVED_IMAGE_PATH = "saved-image-path";

    private final UiEventLogger mUiEventLogger;
    private final ScrollCaptureController mScrollCaptureController;
    private final Executor mUiExecutor;
    private final Executor mBackgroundExecutor;
    private final ImageExporter mImageExporter;

    // If true, the activity is re-loading an image from storage, which should either succeed and
    // populate the UI or fail and finish the activity.
    private boolean mRestoringInstance;
    private final LongScreenshotHolder mLongScreenshotHolder;

    private ImageView mPreview;
    private View mSave;
@@ -86,7 +80,6 @@ public class LongScreenshotActivity extends Activity {
    private ListenableFuture<File> mCacheSaveFuture;
    private ListenableFuture<ImageLoader.Result> mCacheLoadFuture;

    private ListenableFuture<LongScreenshot> mLongScreenshotFuture;
    private LongScreenshot mLongScreenshot;

    private enum PendingAction {
@@ -97,13 +90,13 @@ public class LongScreenshotActivity extends Activity {

    @Inject
    public LongScreenshotActivity(UiEventLogger uiEventLogger, ImageExporter imageExporter,
            @Main Executor mainExecutor, @Background Executor bgExecutor, IWindowManager wms,
            Context context, ScrollCaptureController scrollCaptureController) {
            @Main Executor mainExecutor, @Background Executor bgExecutor,
            LongScreenshotHolder longScreenshotHolder) {
        mUiEventLogger = uiEventLogger;
        mUiExecutor = mainExecutor;
        mBackgroundExecutor = bgExecutor;
        mImageExporter = imageExporter;
        mScrollCaptureController = scrollCaptureController;
        mLongScreenshotHolder = longScreenshotHolder;
    }


@@ -152,7 +145,7 @@ public class LongScreenshotActivity extends Activity {
        super.onStart();

        if (mCacheLoadFuture != null) {
            Log.d(TAG, "mRestoringInstance = true");
            Log.d(TAG, "mCacheLoadFuture != null");
            final ListenableFuture<ImageLoader.Result> future = mCacheLoadFuture;
            mCacheLoadFuture.addListener(() -> {
                Log.d(TAG, "cached bitmap load complete");
@@ -170,40 +163,19 @@ public class LongScreenshotActivity extends Activity {
            }, mUiExecutor);
            mCacheLoadFuture = null;
            return;
        }

        if (mLongScreenshotFuture == null) {
            Log.d(TAG, "mLongScreenshotFuture == null");
            // First run through, ensure we have a connection to use (see #onCreate)
            if (mScrollCaptureResponse == null || !mScrollCaptureResponse.isConnected()) {
                Log.e(TAG, "Did not receive a live scroll capture connection, bailing out!");
                finishAndRemoveTask();
                return;
            }
            mLongScreenshotFuture = mScrollCaptureController.run(mScrollCaptureResponse);
            mLongScreenshotFuture.addListener(() -> {
                LongScreenshot longScreenshot;
                try {
                    longScreenshot = mLongScreenshotFuture.get();
                } catch (CancellationException | InterruptedException | ExecutionException e) {
                    Log.e(TAG, "Error capturing long screenshot!", e);
                    finishAndRemoveTask();
                    return;
                }
                if (longScreenshot.getHeight() == 0) {
                    Log.e(TAG, "Got a zero height result");
        } else {
            LongScreenshot longScreenshot = mLongScreenshotHolder.takeLongScreenshot();
            if (longScreenshot != null) {
                onLongScreenshotReceived(longScreenshot);
            } else {
                Log.e(TAG, "No long screenshot available!");
                finishAndRemoveTask();
                    return;
            }
                onCaptureCompleted(longScreenshot);
            }, mUiExecutor);
        } else {
            Log.d(TAG, "mLongScreenshotFuture != null");
        }
    }

    private void onCaptureCompleted(LongScreenshot longScreenshot) {
        Log.d(TAG, "onCaptureCompleted(longScreenshot=" + longScreenshot + ")");
    private void onLongScreenshotReceived(LongScreenshot longScreenshot) {
        Log.d(TAG, "onLongScreenshotReceived(longScreenshot=" + longScreenshot + ")");
        mLongScreenshot = longScreenshot;
        mPreview.setImageDrawable(mLongScreenshot.getDrawable());
        updateImageDimensions();
@@ -283,9 +255,6 @@ public class LongScreenshotActivity extends Activity {
            }
            cleanupCache();

            if (mLongScreenshotFuture != null) {
                mLongScreenshotFuture.cancel(true);
            }
            if (mLongScreenshot != null) {
                mLongScreenshot.release();
            }
+59 −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.systemui.screenshot;

import com.android.systemui.dagger.SysUISingleton;

import java.util.concurrent.atomic.AtomicReference;

import javax.inject.Inject;

/**
 * LongScreenshotHolder holds on to 1 LongScreenshot reference to facilitate indirect in-process
 * passing.
 */
@SysUISingleton
public class LongScreenshotHolder {
    private final AtomicReference<ScrollCaptureController.LongScreenshot> mLongScreenshot;

    @Inject
    public LongScreenshotHolder() {
        mLongScreenshot = new AtomicReference<>();
    }

    /**
     * Set the holder's stored LongScreenshot.
     */
    public void setLongScreenshot(ScrollCaptureController.LongScreenshot longScreenshot) {
        mLongScreenshot.set(longScreenshot);
    }

    /**
     * @return true if the holder has a non-null LongScreenshot.
     */
    public boolean hasLongScreenshot() {
        return mLongScreenshot.get() != null;
    }

    /**
     * Return the current stored LongScreenshot, clear the holder's storage.
     */
    public ScrollCaptureController.LongScreenshot takeLongScreenshot() {
        return mLongScreenshot.getAndSet(null);
    }

}
+28 −7
Original line number Diff line number Diff line
@@ -191,6 +191,8 @@ public class ScreenshotController {
    private final ScrollCaptureClient mScrollCaptureClient;
    private final PhoneWindow mWindow;
    private final DisplayManager mDisplayManager;
    private final ScrollCaptureController mScrollCaptureController;
    private final LongScreenshotHolder mLongScreenshotHolder;

    private ScreenshotView mScreenshotView;
    private Bitmap mScreenBitmap;
@@ -233,13 +235,17 @@ public class ScreenshotController {
            ScrollCaptureClient scrollCaptureClient,
            UiEventLogger uiEventLogger,
            ImageExporter imageExporter,
            @Main Executor mainExecutor) {
            @Main Executor mainExecutor,
            ScrollCaptureController scrollCaptureController,
            LongScreenshotHolder longScreenshotHolder) {
        mScreenshotSmartActions = screenshotSmartActions;
        mNotificationsController = screenshotNotificationsController;
        mScrollCaptureClient = scrollCaptureClient;
        mUiEventLogger = uiEventLogger;
        mImageExporter = imageExporter;
        mMainExecutor = mainExecutor;
        mScrollCaptureController = scrollCaptureController;
        mLongScreenshotHolder = longScreenshotHolder;
        mBgExecutor = Executors.newSingleThreadExecutor();

        mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
@@ -569,15 +575,30 @@ public class ScreenshotController {
            }
            Log.d(TAG, "ScrollCapture: connected to window ["
                    + mLastScrollCaptureResponse.getWindowTitle() + "]");
            final Intent intent = new Intent(mContext, LongScreenshotActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.putExtra(LongScreenshotActivity.EXTRA_CAPTURE_RESPONSE,
                    mLastScrollCaptureResponse);

            final ScrollCaptureResponse response = mLastScrollCaptureResponse;
            mScreenshotView.showScrollChip(/* onClick */ () -> {
                // Clear the reference to prevent close() in dismissScreenshot
                mLastScrollCaptureResponse = null;
                final ListenableFuture<ScrollCaptureController.LongScreenshot> future =
                        mScrollCaptureController.run(response);
                future.addListener(() -> {
                    ScrollCaptureController.LongScreenshot longScreenshot;
                    try {
                        longScreenshot = future.get();
                    } catch (CancellationException | InterruptedException | ExecutionException e) {
                        Log.e(TAG, "Exception", e);
                        return;
                    }

                    mLongScreenshotHolder.setLongScreenshot(longScreenshot);

                    final Intent intent = new Intent(mContext, LongScreenshotActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    mContext.startActivity(intent);

                    dismissScreenshot(false);
                }, mMainExecutor);
            });
        } catch (CancellationException e) {
            // Ignore