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

Commit 0edac713 authored by Matt Casey's avatar Matt Casey
Browse files

Move scroll capture back to ScreenshotController.

Makes timing more flexible for acquisition, allowing for delayed content
loading.

Bug: 173700533
Test: Verify scroll content still loads with longer timeouts
Change-Id: I1cab53a6bda671854fb24203063c780923e34572
parent cb071176
Loading
Loading
Loading
Loading
+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