From bd67f638822eeb583425b3161d9443ad3efc4921 Mon Sep 17 00:00:00 2001 From: Miranda Kephart Date: Thu, 28 May 2020 15:04:56 -0400 Subject: [PATCH] Fix screenshot UI for insets Previously, the screenshot UI was shown on top of display cutouts. We want the animation (e.g. flash) to display over any insets, but the screenshot preview and actions should respect insets. This change makes the static UI respect insets, and sets the animation so that it smoothly animates to the location of the static preview. Bug: 153404471 Bug: 155272789 Fix: 153404471 Fix: 155272789 Test: manual -- tested full, partial, and from overview, with various display cutouts on and off and with navbar set to gestural/2/3-button mode. Change-Id: I85100a674e1736dd6c198ee85fa07cd700e839b4 --- .../SystemUI/res/layout/global_screenshot.xml | 68 ++------------ .../res/layout/global_screenshot_static.xml | 84 ++++++++++++++++++ packages/SystemUI/res/values/dimens.xml | 4 +- .../systemui/screenshot/GlobalScreenshot.java | 88 ++++++++----------- 4 files changed, 129 insertions(+), 115 deletions(-) create mode 100644 packages/SystemUI/res/layout/global_screenshot_static.xml diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index d469e0f187e05..fce4610b934bc 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -14,9 +14,8 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - @@ -24,72 +23,18 @@ android:id="@+id/global_screenshot_actions_background" android:layout_height="@dimen/screenshot_bg_protection_height" android:layout_width="match_parent" + android:layout_gravity="bottom" android:alpha="0.0" - android:src="@drawable/screenshot_actions_background_protection" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent"/> - - - - + android:src="@drawable/screenshot_actions_background_protection"/> - - - - - + + diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml new file mode 100644 index 0000000000000..a46823d9bc386 --- /dev/null +++ b/packages/SystemUI/res/layout/global_screenshot_static.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 7f1763d2dec1f..a7d176443c558 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -308,11 +308,11 @@ 80dp 242dp 6dp - 48dp + 32dp 16dp 48dp 8dp - 32dp + 16dp 10dp 6dp 8dp diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 33d692f8e1e57..a9d3772a0fdb8 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -64,7 +64,6 @@ import android.util.Slog; import android.view.Display; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.Surface; import android.view.SurfaceControl; import android.view.View; import android.view.ViewGroup; @@ -212,8 +211,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private boolean mDirectionLTR = true; private boolean mOrientationPortrait = true; - private float mScreenshotOffsetXPx; - private float mScreenshotOffsetYPx; private float mCornerSizeX; private float mDismissDeltaY; @@ -273,8 +270,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mDisplayMetrics = new DisplayMetrics(); mDisplay.getRealMetrics(mDisplayMetrics); - mScreenshotOffsetXPx = resources.getDimensionPixelSize(R.dimen.screenshot_offset_x); - mScreenshotOffsetYPx = resources.getDimensionPixelSize(R.dimen.screenshot_offset_y); mCornerSizeX = resources.getDimensionPixelSize(R.dimen.global_screenshot_x_scale); mDismissDeltaY = resources.getDimensionPixelSize(R.dimen.screenshot_dismissal_height_delta); @@ -448,12 +443,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset * Takes a screenshot of the current display and shows an animation. */ private void takeScreenshot(Consumer finisher, Rect crop) { + // copy the input Rect, since SurfaceControl.screenshot can mutate it + Rect screenRect = new Rect(crop); int rot = mDisplay.getRotation(); int width = crop.width(); int height = crop.height(); - - Rect screenRect = new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels); - takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect); } @@ -483,12 +477,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset onConfigChanged(mContext.getResources().getConfiguration()); - if (mDismissAnimation != null && mDismissAnimation.isRunning()) { mDismissAnimation.cancel(); } // Start the post-screenshot animation - startAnimation(finisher, screenRect.width(), screenRect.height(), screenRect); + startAnimation(finisher, mScreenBitmap.getWidth(), mScreenBitmap.getHeight(), screenRect); } void takeScreenshot(Consumer finisher, Runnable onComplete) { @@ -691,8 +684,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset /** * Starts the animation after taking the screenshot */ - private void startAnimation(final Consumer finisher, int w, int h, - @Nullable Rect screenRect) { + private void startAnimation( + final Consumer finisher, int bitmapWidth, int bitmapHeight, Rect screenRect) { // If power save is on, show a toast so there is some visual indication that a // screenshot has been taken. PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); @@ -700,21 +693,28 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show(); } - mScreenshotAnimation = createScreenshotDropInAnimation(w, h, screenRect); - - saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() { - @Override - void onActionsReady(SavedImageData imageData) { - showUiOnActionsReady(imageData); - } - }); mScreenshotHandler.post(() -> { if (!mScreenshotLayout.isAttachedToWindow()) { mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams); } - mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this); + mScreenshotAnimatedView.setImageBitmap(mScreenBitmap); + mScreenshotPreview.setImageBitmap(mScreenBitmap); + + // make static preview invisible (from gone) so we can query its location on screen + mScreenshotPreview.setVisibility(View.INVISIBLE); mScreenshotHandler.post(() -> { + mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this); + + mScreenshotAnimation = + createScreenshotDropInAnimation(bitmapWidth, bitmapHeight, screenRect); + + saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() { + @Override + void onActionsReady(SavedImageData imageData) { + showUiOnActionsReady(imageData); + } + }); // Play the shutter sound to notify that we've taken a screenshot mCameraSound.play(MediaActionSound.SHUTTER_CLICK); @@ -726,18 +726,13 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset }); } - private AnimatorSet createScreenshotDropInAnimation(int width, int height, Rect bounds) { - float screenWidth = mDisplayMetrics.widthPixels; - float screenHeight = mDisplayMetrics.heightPixels; + private AnimatorSet createScreenshotDropInAnimation( + int bitmapWidth, int bitmapHeight, Rect bounds) { + Rect previewBounds = new Rect(); + mScreenshotPreview.getBoundsOnScreen(previewBounds); - int rotation = mContext.getDisplay().getRotation(); - float cornerScale; - if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) { - cornerScale = (mCornerSizeX / screenHeight); - } else { - cornerScale = (mCornerSizeX / screenWidth); - } - float currentScale = width / screenWidth; + float cornerScale = mCornerSizeX / (mOrientationPortrait ? bitmapWidth : bitmapHeight); + float currentScale = bounds.height() / (float) bitmapHeight; mScreenshotAnimatedView.setScaleX(currentScale); mScreenshotAnimatedView.setScaleY(currentScale); @@ -745,9 +740,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mScreenshotAnimatedView.setPivotX(0); mScreenshotAnimatedView.setPivotY(0); - mScreenshotAnimatedView.setImageBitmap(mScreenBitmap); - mScreenshotPreview.setImageBitmap(mScreenBitmap); - AnimatorSet dropInAnimation = new AnimatorSet(); ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1); flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS); @@ -761,15 +753,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset flashOutAnimator.addUpdateListener(animation -> mScreenshotFlash.setAlpha((float) animation.getAnimatedValue())); + // animate from the current location, to the static preview location final PointF startPos = new PointF(bounds.centerX(), bounds.centerY()); - float finalX; - if (mDirectionLTR) { - finalX = mScreenshotOffsetXPx + screenWidth * cornerScale / 2f; - } else { - finalX = screenWidth - mScreenshotOffsetXPx - screenWidth * cornerScale / 2f; - } - float finalY = screenHeight - mScreenshotOffsetYPx - screenHeight * cornerScale / 2f; - final PointF finalPos = new PointF(finalX, finalY); + final PointF finalPos = new PointF(previewBounds.centerX(), previewBounds.centerY()); ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1); toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS); @@ -795,13 +781,13 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset if (t < xPositionPct) { float xCenter = MathUtils.lerp(startPos.x, finalPos.x, mFastOutSlowIn.getInterpolation(t / xPositionPct)); - mScreenshotAnimatedView.setX(xCenter - screenWidth * currentScaleX / 2f); + mScreenshotAnimatedView.setX(xCenter - bitmapWidth * currentScaleX / 2f); } else { - mScreenshotAnimatedView.setX(finalPos.x - screenWidth * currentScaleX / 2f); + mScreenshotAnimatedView.setX(finalPos.x - bitmapWidth * currentScaleX / 2f); } - float yCenter = MathUtils.lerp(startPos.y, finalPos.y, - mFastOutSlowIn.getInterpolation(t)); - mScreenshotAnimatedView.setY(yCenter - screenHeight * currentScaleY / 2f); + float yCenter = MathUtils.lerp( + startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t)); + mScreenshotAnimatedView.setY(yCenter - bitmapHeight * currentScaleY / 2f); }); toCorner.addListener(new AnimatorListenerAdapter() { @@ -824,10 +810,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset super.onAnimationEnd(animation); mScreenshotAnimatedView.setScaleX(1); mScreenshotAnimatedView.setScaleY(1); - mScreenshotAnimatedView.setX(finalPos.x - width * cornerScale / 2f); - mScreenshotAnimatedView.setY(finalPos.y - height * cornerScale / 2f); - Rect bounds = new Rect(); - mDismissButton.getBoundsOnScreen(bounds); + mScreenshotAnimatedView.setX(finalPos.x - bounds.width() * cornerScale / 2f); + mScreenshotAnimatedView.setY(finalPos.y - bounds.height() * cornerScale / 2f); mScreenshotAnimatedView.setVisibility(View.GONE); mScreenshotPreview.setVisibility(View.VISIBLE); mDismissButton.setVisibility(View.VISIBLE);