diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index 5bd181c824923..93bd58113bc28 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -20,6 +20,11 @@ android:theme="@style/Screenshot" android:layout_width="match_parent" android:layout_height="match_parent"> + + diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml index 0ae2f7273c60d..8fb9aa63a5a36 100644 --- a/packages/SystemUI/res/layout/long_screenshot.xml +++ b/packages/SystemUI/res/layout/long_screenshot.xml @@ -62,6 +62,7 @@ android:paddingHorizontal="48dp" android:paddingTop="8dp" android:paddingBottom="42dp" + android:alpha="0" app:layout_constrainedHeight="true" app:layout_constrainedWidth="true" app:layout_constraintTop_toBottomOf="@id/save" @@ -72,6 +73,16 @@ tools:minHeight="100dp" tools:minWidth="100dp" /> + + viewRatio) { // Image is full width and height is constrained, compute extra padding to inform // CropView imageHeight = (int) (previewHeight * viewRatio / imageRatio); - int extraPadding = (previewHeight - imageHeight) / 2; + extraPadding = (previewHeight - imageHeight) / 2; mCropView.setExtraPadding(extraPadding + mPreview.getPaddingTop(), extraPadding + mPreview.getPaddingBottom()); imageTop += (previewHeight - imageHeight) / 2; mCropView.setExtraPadding(extraPadding, extraPadding); mCropView.setImageWidth(previewWidth); + scale = previewWidth / (float) mPreview.getDrawable().getIntrinsicWidth(); } else { imageWidth = (int) (previewWidth * imageRatio / viewRatio); imageLeft += (previewWidth - imageWidth) / 2; // Image is full height mCropView.setExtraPadding(mPreview.getPaddingTop(), mPreview.getPaddingBottom()); mCropView.setImageWidth((int) (previewHeight * imageRatio)); + scale = previewHeight / (float) mPreview.getDrawable().getIntrinsicHeight(); } // Update transition view's position and scale. @@ -439,5 +475,20 @@ public class LongScreenshotActivity extends Activity { params.width = boundaries.width(); params.height = boundaries.height(); mTransitionView.setLayoutParams(params); + + ConstraintLayout.LayoutParams enterTransitionParams = + (ConstraintLayout.LayoutParams) mEnterTransitionView.getLayoutParams(); + float topFraction = Math.max(0, + -mLongScreenshot.getTop() / (float) mLongScreenshot.getHeight()); + enterTransitionParams.width = (int) (scale * drawable.getIntrinsicWidth()); + enterTransitionParams.height = (int) (scale * mLongScreenshot.getPageHeight()); + mEnterTransitionView.setLayoutParams(enterTransitionParams); + + Matrix matrix = new Matrix(); + matrix.setScale(scale, scale); + matrix.postTranslate(0, -scale * drawable.getIntrinsicHeight() * topFraction); + mEnterTransitionView.setImageMatrix(matrix); + mEnterTransitionView.setTranslationY( + topFraction * previewHeight + mPreview.getPaddingTop() + extraPadding); } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 2011c0d3458c6..b1e589f274a4c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -598,7 +598,7 @@ public class ScreenshotController { // No connection means that the target window wasn't found // or that it cannot support scroll capture. Log.d(TAG, "ScrollCapture: " + mLastScrollCaptureResponse.getDescription() + " [" - + mLastScrollCaptureResponse.getWindowTitle() + "]"); + + mLastScrollCaptureResponse.getWindowTitle() + "]"); return; } Log.d(TAG, "ScrollCapture: connected to window [" @@ -606,6 +606,7 @@ public class ScreenshotController { final ScrollCaptureResponse response = mLastScrollCaptureResponse; mScreenshotView.showScrollChip(/* onClick */ () -> { + mScreenshotView.prepareScrollingTransition(response, mScreenBitmap); // Clear the reference to prevent close() in dismissScreenshot mLastScrollCaptureResponse = null; final ListenableFuture future = @@ -623,9 +624,14 @@ public class ScreenshotController { 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); + Pair transition = + ActivityOptions.startSharedElementAnimation( + mWindow, new ScreenshotExitTransitionCallbacks(), null, + Pair.create(mScreenshotView.getScrollablePreview(), + ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)); + transition.second.startExit(); + mContext.startActivity(intent, transition.first.toBundle()); }, mMainExecutor); }); } catch (CancellationException e) { @@ -649,7 +655,8 @@ public class ScreenshotController { } @Override - public void onWindowDetached() { } + public void onWindowDetached() { + } }); } @@ -847,24 +854,9 @@ public class ScreenshotController { */ private Supplier getActionTransitionSupplier() { return () -> { - ExitTransitionCallbacks cb = new ExitTransitionCallbacks() { - @Override - public boolean isReturnTransitionAllowed() { - return false; - } - - @Override - public void hideSharedElements() { - finishDismiss(); - } - - @Override - public void onFinish() { - } - }; - Pair transition = - ActivityOptions.startSharedElementAnimation(mWindow, cb, null, + ActivityOptions.startSharedElementAnimation( + mWindow, new ScreenshotExitTransitionCallbacks(), null, Pair.create(mScreenshotView.getScreenshotPreview(), ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)); transition.second.startExit(); @@ -950,4 +942,20 @@ public class ScreenshotController { } return matchWithinTolerance; } + + private class ScreenshotExitTransitionCallbacks implements ExitTransitionCallbacks { + @Override + public boolean isReturnTransitionAllowed() { + return false; + } + + @Override + public void hideSharedElements() { + finishDismiss(); + } + + @Override + public void onFinish() { + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index a98c79275e0e3..c33c2dbc16a0b 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -40,6 +40,7 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Insets; +import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; @@ -58,6 +59,7 @@ import android.view.DisplayCutout; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; +import android.view.ScrollCaptureResponse; import android.view.TouchDelegate; import android.view.View; import android.view.ViewGroup; @@ -72,6 +74,8 @@ import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; +import androidx.constraintlayout.widget.ConstraintLayout; + import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition; @@ -126,9 +130,11 @@ public class ScreenshotView extends FrameLayout implements private boolean mDirectionLTR; private ScreenshotSelectorView mScreenshotSelectorView; + private ImageView mScrollingScrim; private View mScreenshotStatic; private ImageView mScreenshotPreview; private View mScreenshotPreviewBorder; + private ImageView mScrollablePreview; private ImageView mScreenshotFlash; private ImageView mActionsContainerBackground; private HorizontalScrollView mActionsContainer; @@ -267,6 +273,7 @@ public class ScreenshotView extends FrameLayout implements @Override // View protected void onFinishInflate() { + mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim)); mScreenshotStatic = requireNonNull(findViewById(R.id.global_screenshot_static)); mScreenshotPreview = requireNonNull(findViewById(R.id.global_screenshot_preview)); mScreenshotPreviewBorder = requireNonNull( @@ -280,6 +287,7 @@ public class ScreenshotView extends FrameLayout implements mBackgroundProtection = requireNonNull( findViewById(R.id.global_screenshot_actions_background)); mDismissButton = requireNonNull(findViewById(R.id.global_screenshot_dismiss_button)); + mScrollablePreview = requireNonNull(findViewById(R.id.screenshot_scrollable_preview)); mScreenshotFlash = requireNonNull(findViewById(R.id.global_screenshot_flash)); mScreenshotSelectorView = requireNonNull(findViewById(R.id.global_screenshot_selector)); mShareChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_share_chip)); @@ -328,6 +336,10 @@ public class ScreenshotView extends FrameLayout implements return mScreenshotPreview; } + View getScrollablePreview() { + return mScrollablePreview; + } + /** * Set up the logger and callback on dismissal. * @@ -701,6 +713,38 @@ public class ScreenshotView extends FrameLayout implements } } + private Rect scrollableAreaOnScreen(ScrollCaptureResponse response) { + Rect r = new Rect(response.getBoundsInWindow()); + Rect windowInScreen = response.getWindowBounds(); + r.offset(windowInScreen.left, windowInScreen.top); + r.intersect(new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); + return r; + } + + void prepareScrollingTransition(ScrollCaptureResponse response, Bitmap screenBitmap) { + Rect scrollableArea = scrollableAreaOnScreen(response); + float scale = mCornerSizeX + / (mOrientationPortrait ? screenBitmap.getWidth() : screenBitmap.getHeight()); + ConstraintLayout.LayoutParams params = + (ConstraintLayout.LayoutParams) mScrollablePreview.getLayoutParams(); + + params.width = (int) (scale * scrollableArea.width()); + params.height = (int) (scale * scrollableArea.height()); + Matrix matrix = new Matrix(); + matrix.setScale(scale, scale); + matrix.postTranslate(0, -scrollableArea.top * scale); + + mScrollablePreview.setTranslationX(scale * scrollableArea.left); + mScrollablePreview.setTranslationY(scale * scrollableArea.top); + mScrollablePreview.setImageMatrix(matrix); + + mScrollingScrim.setImageBitmap(screenBitmap); + mScrollingScrim.setVisibility(View.VISIBLE); + mScrollablePreview.setImageBitmap(screenBitmap); + mScrollablePreview.setVisibility(View.VISIBLE); + createScreenshotFadeDismissAnimation(true).start(); + } + boolean isDismissing() { return (mDismissAnimation != null && mDismissAnimation.isRunning()); } @@ -801,7 +845,7 @@ public class ScreenshotView extends FrameLayout implements transition.action.actionIntent.send(); // fade out non-preview UI - createScreenshotFadeDismissAnimation().start(); + createScreenshotFadeDismissAnimation(false).start(); } catch (PendingIntent.CanceledException e) { mPendingSharedTransition = false; if (transition.onCancelRunnable != null) { @@ -839,7 +883,7 @@ public class ScreenshotView extends FrameLayout implements return animSet; } - private ValueAnimator createScreenshotFadeDismissAnimation() { + ValueAnimator createScreenshotFadeDismissAnimation(boolean fadePreview) { ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1); alphaAnim.addUpdateListener(animation -> { float alpha = 1 - animation.getAnimatedFraction(); @@ -847,6 +891,10 @@ public class ScreenshotView extends FrameLayout implements mActionsContainerBackground.setAlpha(alpha); mActionsContainer.setAlpha(alpha); mBackgroundProtection.setAlpha(alpha); + mScreenshotPreviewBorder.setAlpha(alpha); + if (fadePreview) { + mScreenshotPreview.setAlpha(alpha); + } }); alphaAnim.setDuration(600); return alphaAnim; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java index 2863074bee0a9..94e3149487797 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java @@ -405,6 +405,10 @@ public class ScrollCaptureClient { return new Rect(mWindowBounds); } + public Rect getBoundsInWindow() { + return new Rect(mBoundsInWindow); + } + @Override public int getMaxTiles() { return mMaxTiles;