Merge "Move long screenshot UI to an Activity" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
3a8a885261
@@ -334,6 +334,11 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<activity android:name=".screenshot.LongScreenshotActivity"
|
||||||
|
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
|
||||||
|
android:process=":screenshot"
|
||||||
|
android:finishOnTaskLaunch="true" />
|
||||||
|
|
||||||
<activity android:name=".screenrecord.ScreenRecordDialog"
|
<activity android:name=".screenrecord.ScreenRecordDialog"
|
||||||
android:theme="@style/ScreenRecord"
|
android:theme="@style/ScreenRecord"
|
||||||
android:showForAllUsers="true"
|
android:showForAllUsers="true"
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.android.systemui.ForegroundServicesDialog;
|
|||||||
import com.android.systemui.keyguard.WorkLockActivity;
|
import com.android.systemui.keyguard.WorkLockActivity;
|
||||||
import com.android.systemui.people.PeopleSpaceActivity;
|
import com.android.systemui.people.PeopleSpaceActivity;
|
||||||
import com.android.systemui.screenrecord.ScreenRecordDialog;
|
import com.android.systemui.screenrecord.ScreenRecordDialog;
|
||||||
|
import com.android.systemui.screenshot.LongScreenshotActivity;
|
||||||
import com.android.systemui.settings.brightness.BrightnessDialog;
|
import com.android.systemui.settings.brightness.BrightnessDialog;
|
||||||
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
|
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
|
||||||
import com.android.systemui.tuner.TunerActivity;
|
import com.android.systemui.tuner.TunerActivity;
|
||||||
@@ -99,4 +100,10 @@ public abstract class DefaultActivityBinder {
|
|||||||
@IntoMap
|
@IntoMap
|
||||||
@ClassKey(PeopleSpaceActivity.class)
|
@ClassKey(PeopleSpaceActivity.class)
|
||||||
public abstract Activity bindPeopleSpaceActivity(PeopleSpaceActivity activity);
|
public abstract Activity bindPeopleSpaceActivity(PeopleSpaceActivity activity);
|
||||||
|
|
||||||
|
/** Inject into LongScreenshotActivity. */
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(LongScreenshotActivity.class)
|
||||||
|
public abstract Activity bindLongScreenshotActivity(LongScreenshotActivity activity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.app.Activity;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.android.internal.logging.UiEventLogger;
|
||||||
|
import com.android.systemui.R;
|
||||||
|
import com.android.systemui.dagger.qualifiers.Background;
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LongScreenshotActivity acquires bitmap data for a long screenshot and lets the user trim the top
|
||||||
|
* and bottom before saving/sharing/editing.
|
||||||
|
*/
|
||||||
|
public class LongScreenshotActivity extends Activity {
|
||||||
|
private static final String TAG = "LongScreenshotActivity";
|
||||||
|
|
||||||
|
private final UiEventLogger mUiEventLogger;
|
||||||
|
private final ScrollCaptureController mScrollCaptureController;
|
||||||
|
|
||||||
|
private ImageView mPreview;
|
||||||
|
private View mSave;
|
||||||
|
private View mCancel;
|
||||||
|
private View mEdit;
|
||||||
|
private View mShare;
|
||||||
|
private CropView mCropView;
|
||||||
|
private MagnifierView mMagnifierView;
|
||||||
|
|
||||||
|
private enum PendingAction {
|
||||||
|
SHARE,
|
||||||
|
EDIT,
|
||||||
|
SAVE
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public LongScreenshotActivity(UiEventLogger uiEventLogger,
|
||||||
|
ImageExporter imageExporter,
|
||||||
|
@Main Executor mainExecutor,
|
||||||
|
@Background Executor bgExecutor,
|
||||||
|
Context context) {
|
||||||
|
mUiEventLogger = uiEventLogger;
|
||||||
|
|
||||||
|
mScrollCaptureController = new ScrollCaptureController(context,
|
||||||
|
ScreenshotController.sScrollConnection, mainExecutor, bgExecutor, imageExporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.long_screenshot);
|
||||||
|
|
||||||
|
mPreview = findViewById(R.id.preview);
|
||||||
|
mSave = findViewById(R.id.save);
|
||||||
|
mCancel = findViewById(R.id.cancel);
|
||||||
|
mEdit = findViewById(R.id.edit);
|
||||||
|
mShare = findViewById(R.id.share);
|
||||||
|
mCropView = findViewById(R.id.crop_view);
|
||||||
|
mMagnifierView = findViewById(R.id.magnifier);
|
||||||
|
mCropView.setCropInteractionListener(mMagnifierView);
|
||||||
|
|
||||||
|
mSave.setOnClickListener(this::onClicked);
|
||||||
|
mCancel.setOnClickListener(this::onClicked);
|
||||||
|
mEdit.setOnClickListener(this::onClicked);
|
||||||
|
mShare.setOnClickListener(this::onClicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
if (mPreview.getDrawable() == null) {
|
||||||
|
doCapture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableButtons() {
|
||||||
|
mSave.setEnabled(false);
|
||||||
|
mCancel.setEnabled(false);
|
||||||
|
mEdit.setEnabled(false);
|
||||||
|
mShare.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doEdit(Uri uri) {
|
||||||
|
String editorPackage = getString(R.string.config_screenshotEditor);
|
||||||
|
Intent intent = new Intent(Intent.ACTION_EDIT);
|
||||||
|
if (!TextUtils.isEmpty(editorPackage)) {
|
||||||
|
intent.setComponent(ComponentName.unflattenFromString(editorPackage));
|
||||||
|
}
|
||||||
|
intent.setType("image/png");
|
||||||
|
intent.setData(uri);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
| Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
|
|
||||||
|
startActivityAsUser(intent, UserHandle.CURRENT);
|
||||||
|
finishAndRemoveTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doShare(Uri uri) {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
|
intent.setType("image/png");
|
||||||
|
intent.setData(uri);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
Intent sharingChooserIntent = Intent.createChooser(intent, null)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
|
||||||
|
startActivityAsUser(sharingChooserIntent, UserHandle.CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onClicked(View v) {
|
||||||
|
int id = v.getId();
|
||||||
|
v.setPressed(true);
|
||||||
|
disableButtons();
|
||||||
|
if (id == R.id.save) {
|
||||||
|
startExport(PendingAction.SAVE);
|
||||||
|
} else if (id == R.id.cancel) {
|
||||||
|
finishAndRemoveTask();
|
||||||
|
} else if (id == R.id.edit) {
|
||||||
|
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_EDIT);
|
||||||
|
startExport(PendingAction.EDIT);
|
||||||
|
} else if (id == R.id.share) {
|
||||||
|
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_SHARE);
|
||||||
|
startExport(PendingAction.SHARE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startExport(PendingAction action) {
|
||||||
|
mScrollCaptureController.startExport(mCropView.getTopBoundary(),
|
||||||
|
mCropView.getBottomBoundary(), new ScrollCaptureController.ExportCallback() {
|
||||||
|
@Override
|
||||||
|
public void onError() {
|
||||||
|
Log.e(TAG, "Error exporting image data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExportComplete(Uri outputUri) {
|
||||||
|
switch (action) {
|
||||||
|
case EDIT:
|
||||||
|
doEdit(outputUri);
|
||||||
|
break;
|
||||||
|
case SHARE:
|
||||||
|
doShare(outputUri);
|
||||||
|
break;
|
||||||
|
case SAVE:
|
||||||
|
// Nothing more to do
|
||||||
|
finishAndRemoveTask();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doCapture() {
|
||||||
|
mScrollCaptureController.start(new ScrollCaptureController.ScrollCaptureCallback() {
|
||||||
|
@Override
|
||||||
|
public void onError() {
|
||||||
|
Log.e(TAG, "Error!");
|
||||||
|
finishAndRemoveTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete(ImageTileSet imageTileSet) {
|
||||||
|
Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
|
||||||
|
+ imageTileSet.getHeight());
|
||||||
|
mPreview.setImageDrawable(imageTileSet.getDrawable());
|
||||||
|
mMagnifierView.setImageTileset(imageTileSet);
|
||||||
|
mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ import android.app.Notification;
|
|||||||
import android.app.WindowContext;
|
import android.app.WindowContext;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Insets;
|
import android.graphics.Insets;
|
||||||
@@ -100,6 +101,8 @@ import javax.inject.Inject;
|
|||||||
public class ScreenshotController {
|
public class ScreenshotController {
|
||||||
private static final String TAG = logTag(ScreenshotController.class);
|
private static final String TAG = logTag(ScreenshotController.class);
|
||||||
|
|
||||||
|
public static ScrollCaptureClient.Connection sScrollConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POD used in the AsyncTask which saves an image in the background.
|
* POD used in the AsyncTask which saves an image in the background.
|
||||||
*/
|
*/
|
||||||
@@ -597,21 +600,12 @@ public class ScreenshotController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void runScrollCapture(ScrollCaptureClient.Connection connection) {
|
private void runScrollCapture(ScrollCaptureClient.Connection connection) {
|
||||||
cancelTimeout();
|
sScrollConnection = connection; // For LongScreenshotActivity to pick up.
|
||||||
ScrollCaptureController controller = new ScrollCaptureController(mContext, connection,
|
|
||||||
mMainExecutor, mBgExecutor, mImageExporter, mUiEventLogger);
|
|
||||||
controller.attach(mWindow);
|
|
||||||
controller.start(new TakeScreenshotService.RequestCallback() {
|
|
||||||
@Override
|
|
||||||
public void reportError() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
Intent intent = new Intent(mContext, LongScreenshotActivity.class);
|
||||||
public void onFinish() {
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
Log.d(TAG, "onFinish from ScrollCaptureController");
|
mContext.startActivity(intent);
|
||||||
finishDismiss();
|
dismissScreenshot(false);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,29 +16,16 @@
|
|||||||
|
|
||||||
package com.android.systemui.screenshot;
|
package com.android.systemui.screenshot;
|
||||||
|
|
||||||
import android.annotation.IdRes;
|
|
||||||
import android.annotation.UiThread;
|
import android.annotation.UiThread;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewTreeObserver.InternalInsetsInfo;
|
|
||||||
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
|
|
||||||
import com.android.internal.logging.UiEventLogger;
|
|
||||||
import com.android.systemui.R;
|
|
||||||
import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
|
import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
|
||||||
import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
|
import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
|
||||||
import com.android.systemui.screenshot.ScrollCaptureClient.Session;
|
import com.android.systemui.screenshot.ScrollCaptureClient.Session;
|
||||||
import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
|
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
@@ -50,7 +37,7 @@ import java.util.concurrent.Executor;
|
|||||||
/**
|
/**
|
||||||
* Interaction controller between the UI and ScrollCaptureClient.
|
* Interaction controller between the UI and ScrollCaptureClient.
|
||||||
*/
|
*/
|
||||||
public class ScrollCaptureController implements OnComputeInternalInsetsListener {
|
public class ScrollCaptureController {
|
||||||
private static final String TAG = "ScrollCaptureController";
|
private static final String TAG = "ScrollCaptureController";
|
||||||
private static final float MAX_PAGES_DEFAULT = 3f;
|
private static final float MAX_PAGES_DEFAULT = 3f;
|
||||||
|
|
||||||
@@ -64,13 +51,6 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
|
|||||||
private boolean mAtTopEdge;
|
private boolean mAtTopEdge;
|
||||||
private Session mSession;
|
private Session mSession;
|
||||||
|
|
||||||
// TODO: Support saving without additional action.
|
|
||||||
private enum PendingAction {
|
|
||||||
SHARE,
|
|
||||||
EDIT,
|
|
||||||
SAVE
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int MAX_HEIGHT = 12000;
|
public static final int MAX_HEIGHT = 12000;
|
||||||
|
|
||||||
private final Connection mConnection;
|
private final Connection mConnection;
|
||||||
@@ -80,172 +60,59 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
|
|||||||
private final Executor mBgExecutor;
|
private final Executor mBgExecutor;
|
||||||
private final ImageExporter mImageExporter;
|
private final ImageExporter mImageExporter;
|
||||||
private final ImageTileSet mImageTileSet;
|
private final ImageTileSet mImageTileSet;
|
||||||
private final UiEventLogger mUiEventLogger;
|
|
||||||
|
|
||||||
private ZonedDateTime mCaptureTime;
|
private ZonedDateTime mCaptureTime;
|
||||||
private UUID mRequestId;
|
private UUID mRequestId;
|
||||||
private RequestCallback mCallback;
|
private ScrollCaptureCallback mCaptureCallback;
|
||||||
private Window mWindow;
|
|
||||||
private ImageView mPreview;
|
|
||||||
private View mSave;
|
|
||||||
private View mCancel;
|
|
||||||
private View mEdit;
|
|
||||||
private View mShare;
|
|
||||||
private CropView mCropView;
|
|
||||||
private MagnifierView mMagnifierView;
|
|
||||||
|
|
||||||
public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
|
public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
|
||||||
Executor bgExecutor, ImageExporter exporter, UiEventLogger uiEventLogger) {
|
Executor bgExecutor, ImageExporter exporter) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mConnection = connection;
|
mConnection = connection;
|
||||||
mUiExecutor = uiExecutor;
|
mUiExecutor = uiExecutor;
|
||||||
mBgExecutor = bgExecutor;
|
mBgExecutor = bgExecutor;
|
||||||
mImageExporter = exporter;
|
mImageExporter = exporter;
|
||||||
mUiEventLogger = uiEventLogger;
|
|
||||||
mImageTileSet = new ImageTileSet(context.getMainThreadHandler());
|
mImageTileSet = new ImageTileSet(context.getMainThreadHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param window the window to display the preview
|
|
||||||
*/
|
|
||||||
public void attach(Window window) {
|
|
||||||
mWindow = window;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run scroll capture!
|
* Run scroll capture!
|
||||||
*
|
*
|
||||||
* @param callback request callback to report back to the service
|
* @param callback request callback to report back to the service
|
||||||
*/
|
*/
|
||||||
public void start(RequestCallback callback) {
|
public void start(ScrollCaptureCallback callback) {
|
||||||
mCaptureTime = ZonedDateTime.now();
|
mCaptureTime = ZonedDateTime.now();
|
||||||
mRequestId = UUID.randomUUID();
|
mRequestId = UUID.randomUUID();
|
||||||
mCallback = callback;
|
mCaptureCallback = callback;
|
||||||
|
|
||||||
setContentView(R.layout.long_screenshot);
|
|
||||||
mWindow.getDecorView().getViewTreeObserver()
|
|
||||||
.addOnComputeInternalInsetsListener(this);
|
|
||||||
mPreview = findViewById(R.id.preview);
|
|
||||||
|
|
||||||
mSave = findViewById(R.id.save);
|
|
||||||
mCancel = findViewById(R.id.cancel);
|
|
||||||
mEdit = findViewById(R.id.edit);
|
|
||||||
mShare = findViewById(R.id.share);
|
|
||||||
mCropView = findViewById(R.id.crop_view);
|
|
||||||
mMagnifierView = findViewById(R.id.magnifier);
|
|
||||||
mCropView.setCropInteractionListener(mMagnifierView);
|
|
||||||
|
|
||||||
mSave.setOnClickListener(this::onClicked);
|
|
||||||
mCancel.setOnClickListener(this::onClicked);
|
|
||||||
mEdit.setOnClickListener(this::onClicked);
|
|
||||||
mShare.setOnClickListener(this::onClicked);
|
|
||||||
|
|
||||||
float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(),
|
float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(),
|
||||||
SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT);
|
SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT);
|
||||||
mConnection.start(this::startCapture, maxPages);
|
mConnection.start(this::startCapture, maxPages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/** Ensure the entire window is touchable */
|
* @param topCrop [0,1) fraction of the top of the image to be cropped out.
|
||||||
public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
|
* @param bottomCrop (0, 1] fraction to be cropped out, e.g. 0.7 will crop out the bottom 30%.
|
||||||
inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
|
*/
|
||||||
}
|
public void startExport(float topCrop, float bottomCrop, ExportCallback callback) {
|
||||||
|
|
||||||
void disableButtons() {
|
|
||||||
mSave.setEnabled(false);
|
|
||||||
mCancel.setEnabled(false);
|
|
||||||
mEdit.setEnabled(false);
|
|
||||||
mShare.setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onClicked(View v) {
|
|
||||||
Log.d(TAG, "button clicked!");
|
|
||||||
|
|
||||||
int id = v.getId();
|
|
||||||
v.setPressed(true);
|
|
||||||
disableButtons();
|
|
||||||
if (id == R.id.save) {
|
|
||||||
startExport(PendingAction.SAVE);
|
|
||||||
} else if (id == R.id.cancel) {
|
|
||||||
doFinish();
|
|
||||||
} else if (id == R.id.edit) {
|
|
||||||
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_EDIT);
|
|
||||||
startExport(PendingAction.EDIT);
|
|
||||||
} else if (id == R.id.share) {
|
|
||||||
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_SHARE);
|
|
||||||
startExport(PendingAction.SHARE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doFinish() {
|
|
||||||
mPreview.setImageDrawable(null);
|
|
||||||
mMagnifierView.setImageTileset(null);
|
|
||||||
mImageTileSet.clear();
|
|
||||||
mCallback.onFinish();
|
|
||||||
mWindow.getDecorView().getViewTreeObserver()
|
|
||||||
.removeOnComputeInternalInsetsListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startExport(PendingAction action) {
|
|
||||||
Rect croppedPortion = new Rect(
|
Rect croppedPortion = new Rect(
|
||||||
0,
|
0,
|
||||||
(int) (mImageTileSet.getHeight() * mCropView.getTopBoundary()),
|
(int) (mImageTileSet.getHeight() * topCrop),
|
||||||
mImageTileSet.getWidth(),
|
mImageTileSet.getWidth(),
|
||||||
(int) (mImageTileSet.getHeight() * mCropView.getBottomBoundary()));
|
(int) (mImageTileSet.getHeight() * bottomCrop));
|
||||||
ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
|
ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
|
||||||
mBgExecutor, mRequestId, mImageTileSet.toBitmap(croppedPortion), mCaptureTime);
|
mBgExecutor, mRequestId, mImageTileSet.toBitmap(croppedPortion), mCaptureTime);
|
||||||
exportFuture.addListener(() -> {
|
exportFuture.addListener(() -> {
|
||||||
try {
|
try {
|
||||||
ImageExporter.Result result = exportFuture.get();
|
ImageExporter.Result result = exportFuture.get();
|
||||||
if (action == PendingAction.EDIT) {
|
callback.onExportComplete(result.uri);
|
||||||
doEdit(result.uri);
|
|
||||||
} else if (action == PendingAction.SHARE) {
|
|
||||||
doShare(result.uri);
|
|
||||||
}
|
|
||||||
doFinish();
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
Log.e(TAG, "failed to export", e);
|
Log.e(TAG, "failed to export", e);
|
||||||
mCallback.onFinish();
|
callback.onError();
|
||||||
}
|
}
|
||||||
}, mUiExecutor);
|
}, mUiExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doEdit(Uri uri) {
|
|
||||||
String editorPackage = mContext.getString(R.string.config_screenshotEditor);
|
|
||||||
Intent intent = new Intent(Intent.ACTION_EDIT);
|
|
||||||
if (!TextUtils.isEmpty(editorPackage)) {
|
|
||||||
intent.setComponent(ComponentName.unflattenFromString(editorPackage));
|
|
||||||
}
|
|
||||||
intent.setType("image/png");
|
|
||||||
intent.setData(uri);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
|
|
||||||
| Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
||||||
|
|
||||||
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doShare(Uri uri) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
|
||||||
intent.setType("image/png");
|
|
||||||
intent.setData(uri);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
|
|
||||||
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
Intent sharingChooserIntent = Intent.createChooser(intent, null)
|
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
|
|
||||||
mContext.startActivityAsUser(sharingChooserIntent, UserHandle.CURRENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setContentView(@IdRes int id) {
|
|
||||||
mWindow.setContentView(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
<T extends View> T findViewById(@IdRes int res) {
|
|
||||||
return mWindow.findViewById(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void onCaptureResult(CaptureResult result) {
|
private void onCaptureResult(CaptureResult result) {
|
||||||
Log.d(TAG, "onCaptureResult: " + result);
|
Log.d(TAG, "onCaptureResult: " + result);
|
||||||
boolean emptyResult = result.captured.height() == 0;
|
boolean emptyResult = result.captured.height() == 0;
|
||||||
@@ -327,11 +194,26 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
|
|||||||
Log.d(TAG, "afterCaptureComplete");
|
Log.d(TAG, "afterCaptureComplete");
|
||||||
|
|
||||||
if (mImageTileSet.isEmpty()) {
|
if (mImageTileSet.isEmpty()) {
|
||||||
session.end(mCallback::onFinish);
|
mCaptureCallback.onError();
|
||||||
} else {
|
} else {
|
||||||
mPreview.setImageDrawable(mImageTileSet.getDrawable());
|
mCaptureCallback.onComplete(mImageTileSet);
|
||||||
mMagnifierView.setImageTileset(mImageTileSet);
|
|
||||||
mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for image capture completion or error.
|
||||||
|
*/
|
||||||
|
public interface ScrollCaptureCallback {
|
||||||
|
void onComplete(ImageTileSet imageTileSet);
|
||||||
|
void onError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for image export completion or error.
|
||||||
|
*/
|
||||||
|
public interface ExportCallback {
|
||||||
|
void onExportComplete(Uri outputUri);
|
||||||
|
void onError();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user