diff options
| -rw-r--r-- | packages/SystemUI/res/layout/global_screenshot.xml | 5 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java | 144 |
2 files changed, 117 insertions, 32 deletions
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index fce4610b934b..6a235218b32f 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -30,11 +30,10 @@ android:id="@+id/global_screenshot_animated_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center" + android:layout_gravity="top|start" android:visibility="gone" android:elevation="@dimen/screenshot_preview_elevation" - android:background="@drawable/screenshot_rounded_corners" - android:adjustViewBounds="true"/> + android:background="@drawable/screenshot_rounded_corners" /> <ImageView android:id="@+id/global_screenshot_flash" android:layout_width="match_parent" diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index a624479fa63c..29ca0546b4bd 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -41,13 +41,19 @@ import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Color; import android.graphics.Insets; import android.graphics.Outline; import android.graphics.PixelFormat; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.graphics.drawable.InsetDrawable; +import android.graphics.drawable.LayerDrawable; import android.media.MediaActionSound; import android.net.Uri; import android.os.Handler; @@ -449,10 +455,12 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset int rot = mDisplay.getRotation(); int width = crop.width(); int height = crop.height(); - takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect); + takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect, + Insets.NONE, true); } - private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect) { + private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect, + Insets screenInsets, boolean showFlash) { dismissScreenshot("new screenshot requested", true); mScreenBitmap = screenshot; @@ -482,7 +490,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mDismissAnimation.cancel(); } // Start the post-screenshot animation - startAnimation(finisher, mScreenBitmap.getWidth(), mScreenBitmap.getHeight(), screenRect); + startAnimation(finisher, screenRect, screenInsets, showFlash); } void takeScreenshot(Consumer<Uri> finisher, Runnable onComplete) { @@ -498,9 +506,15 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset Insets visibleInsets, int taskId, int userId, ComponentName topComponent, Consumer<Uri> finisher, Runnable onComplete) { // TODO: use task Id, userId, topComponent for smart handler - // TODO: use visibleInsets for animation + mOnCompleteRunnable = onComplete; - takeScreenshot(screenshot, finisher, screenshotScreenBounds); + if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) { + takeScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false); + } else { + takeScreenshot(screenshot, finisher, + new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()), Insets.NONE, + true); + } } /** @@ -621,8 +635,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset } // Clear any references to the bitmap - mScreenshotPreview.setImageBitmap(null); - mScreenshotAnimatedView.setImageBitmap(null); + mScreenshotPreview.setImageDrawable(null); + mScreenshotAnimatedView.setImageDrawable(null); + mScreenshotAnimatedView.setVisibility(View.GONE); mActionsContainerBackground.setVisibility(View.GONE); mActionsContainer.setVisibility(View.GONE); mBackgroundProtection.setAlpha(0f); @@ -688,8 +703,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset /** * Starts the animation after taking the screenshot */ - private void startAnimation( - final Consumer<Uri> finisher, int bitmapWidth, int bitmapHeight, Rect screenRect) { + private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets, + boolean showFlash) { + // 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); @@ -701,9 +717,13 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset if (!mScreenshotLayout.isAttachedToWindow()) { mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams); } - mScreenshotAnimatedView.setImageBitmap(mScreenBitmap); - mScreenshotPreview.setImageBitmap(mScreenBitmap); + mScreenshotAnimatedView.setImageDrawable( + createScreenDrawable(mScreenBitmap, screenInsets)); + setAnimatedViewSize(screenRect.width(), screenRect.height()); + // Show when the animation starts + mScreenshotAnimatedView.setVisibility(View.GONE); + mScreenshotPreview.setImageDrawable(createScreenDrawable(mScreenBitmap, screenInsets)); // make static preview invisible (from gone) so we can query its location on screen mScreenshotPreview.setVisibility(View.INVISIBLE); @@ -711,14 +731,14 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this); mScreenshotAnimation = - createScreenshotDropInAnimation(bitmapWidth, bitmapHeight, screenRect); + createScreenshotDropInAnimation(screenRect, showFlash); saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() { - @Override - void onActionsReady(SavedImageData imageData) { - showUiOnActionsReady(imageData); - } - }); + @Override + void onActionsReady(SavedImageData imageData) { + showUiOnActionsReady(imageData); + } + }); // Play the shutter sound to notify that we've taken a screenshot mCameraSound.play(MediaActionSound.SHUTTER_CLICK); @@ -730,20 +750,17 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset }); } - private AnimatorSet createScreenshotDropInAnimation( - int bitmapWidth, int bitmapHeight, Rect bounds) { + private AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash) { Rect previewBounds = new Rect(); mScreenshotPreview.getBoundsOnScreen(previewBounds); - float cornerScale = mCornerSizeX / (mOrientationPortrait ? bitmapWidth : bitmapHeight); - float currentScale = bounds.height() / (float) bitmapHeight; + float cornerScale = + mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height()); + final float currentScale = 1f; mScreenshotAnimatedView.setScaleX(currentScale); mScreenshotAnimatedView.setScaleY(currentScale); - mScreenshotAnimatedView.setPivotX(0); - mScreenshotAnimatedView.setPivotY(0); - AnimatorSet dropInAnimation = new AnimatorSet(); ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1); flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS); @@ -785,13 +802,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 - bitmapWidth * currentScaleX / 2f); + mScreenshotAnimatedView.setX(xCenter - bounds.width() * currentScaleX / 2f); } else { - mScreenshotAnimatedView.setX(finalPos.x - bitmapWidth * currentScaleX / 2f); + mScreenshotAnimatedView.setX(finalPos.x - bounds.width() * currentScaleX / 2f); } float yCenter = MathUtils.lerp( startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t)); - mScreenshotAnimatedView.setY(yCenter - bitmapHeight * currentScaleY / 2f); + mScreenshotAnimatedView.setY(yCenter - bounds.height() * currentScaleY / 2f); }); toCorner.addListener(new AnimatorListenerAdapter() { @@ -805,8 +822,12 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mScreenshotFlash.setAlpha(0f); mScreenshotFlash.setVisibility(View.VISIBLE); - dropInAnimation.play(flashOutAnimator).after(flashInAnimator); - dropInAnimation.play(flashOutAnimator).with(toCorner); + if (showFlash) { + dropInAnimation.play(flashOutAnimator).after(flashInAnimator); + dropInAnimation.play(flashOutAnimator).with(toCorner); + } else { + dropInAnimation.play(toCorner); + } dropInAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -972,6 +993,71 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset return animSet; } + private void setAnimatedViewSize(int width, int height) { + ViewGroup.LayoutParams layoutParams = mScreenshotAnimatedView.getLayoutParams(); + layoutParams.width = width; + layoutParams.height = height; + mScreenshotAnimatedView.setLayoutParams(layoutParams); + } + + /** Does the aspect ratio of the bitmap with insets removed match the bounds. */ + private boolean aspectRatiosMatch(Bitmap bitmap, Insets bitmapInsets, Rect screenBounds) { + int insettedWidth = bitmap.getWidth() - bitmapInsets.left - bitmapInsets.right; + int insettedHeight = bitmap.getHeight() - bitmapInsets.top - bitmapInsets.bottom; + + if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0 + || bitmap.getHeight() == 0) { + Log.e(TAG, String.format( + "Provided bitmap and insets create degenerate region: %dx%d %s", + bitmap.getWidth(), bitmap.getHeight(), bitmapInsets)); + return false; + } + + float insettedBitmapAspect = ((float) insettedWidth) / insettedHeight; + float boundsAspect = ((float) screenBounds.width()) / screenBounds.height(); + + boolean matchWithinTolerance = Math.abs(insettedBitmapAspect - boundsAspect) < 0.1f; + if (!matchWithinTolerance) { + Log.d(TAG, String.format("aspectRatiosMatch: don't match bitmap: %f, bounds: %f", + insettedBitmapAspect, boundsAspect)); + } + + return matchWithinTolerance; + } + + /** + * Create a drawable using the size of the bitmap and insets as the fractional inset parameters. + */ + private Drawable createScreenDrawable(Bitmap bitmap, Insets insets) { + int insettedWidth = bitmap.getWidth() - insets.left - insets.right; + int insettedHeight = bitmap.getHeight() - insets.top - insets.bottom; + + BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap); + if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0 + || bitmap.getHeight() == 0) { + Log.e(TAG, String.format( + "Can't create insetted drawable, using 0 insets " + + "bitmap and insets create degenerate region: %dx%d %s", + bitmap.getWidth(), bitmap.getHeight(), insets)); + return bitmapDrawable; + } + + InsetDrawable insetDrawable = new InsetDrawable(bitmapDrawable, + -1f * insets.left / insettedWidth, + -1f * insets.top / insettedHeight, + -1f * insets.right / insettedWidth, + -1f * insets.bottom / insettedHeight); + + if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) { + // Are any of the insets negative, meaning the bitmap is smaller than the bounds so need + // to fill in the background of the drawable. + return new LayerDrawable(new Drawable[] { + new ColorDrawable(Color.BLACK), insetDrawable}); + } else { + return insetDrawable; + } + } + /** * Receiver to proxy the share or edit intent, used to clean up the notification and send * appropriate signals to the system (ie. to dismiss the keyguard if necessary). |