diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index 94a6bc566e73e..de19303b4948d 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -14,60 +14,89 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - + + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent"/> + + app:layout_constraintHorizontal_bias="0" + app:layout_constraintWidth_percent="1.0" + app:layout_constraintWidth_max="wrap" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@+id/global_screenshot_preview" + app:layout_constraintEnd_toEndOf="parent"> + + android:contentDescription="@string/screenshot_preview_description" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent"/> + android:contentDescription="@string/screenshot_dismiss_ui_description" + app:layout_constraintStart_toEndOf="@+id/global_screenshot_preview" + app:layout_constraintEnd_toEndOf="@+id/global_screenshot_preview" + app:layout_constraintTop_toTopOf="@+id/global_screenshot_preview" + app:layout_constraintBottom_toTopOf="@+id/global_screenshot_preview"> + android:src="@android:color/white"/> - - + diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml index bd91ddb5f406a..e4ae7c1f58272 100644 --- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml +++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml @@ -19,11 +19,11 @@ android:id="@+id/global_screenshot_action_chip" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginRight="@dimen/screenshot_action_chip_margin_right" + android:layout_marginEnd="@dimen/screenshot_action_chip_margin_right" android:layout_gravity="center" android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical" android:background="@drawable/action_chip_background" - android:alpha="0" + android:alpha="0.0" android:gravity="center"> 20dp 20dp + 400dp 80dp 6dp 48dp diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 581422116c8f8..414828953778d 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -17,7 +17,6 @@ package com.android.systemui.screenshot; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; -import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED; @@ -72,7 +71,6 @@ import android.view.animation.AccelerateInterpolator; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.FrameLayout; -import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Toast; @@ -187,10 +185,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private final View mScreenshotLayout; private final ScreenshotSelectorView mScreenshotSelectorView; - private final ImageView mBackgroundView; - private final ImageView mScreenshotView; + private final ImageView mScreenshotAnimatedView; + private final ImageView mScreenshotPreview; private final ImageView mScreenshotFlash; - private final HorizontalScrollView mActionsContainer; + private final ImageView mActionsContainerBackground; + private final FrameLayout mActionsContainer; private final LinearLayout mActionsView; private final ImageView mBackgroundProtection; private final FrameLayout mDismissButton; @@ -205,8 +204,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private float mScreenshotOffsetXPx; private float mScreenshotOffsetYPx; - private float mScreenshotHeightPx; - private float mDismissButtonSize; private float mCornerSizeX; private float mDismissDeltaY; @@ -244,10 +241,19 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset // Inflate the screenshot layout mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null); - mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_background); - mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot); - mScreenshotView.setClipToOutline(true); - mScreenshotView.setOutlineProvider(new ViewOutlineProvider() { + mScreenshotAnimatedView = + mScreenshotLayout.findViewById(R.id.global_screenshot_animated_view); + mScreenshotAnimatedView.setClipToOutline(true); + mScreenshotAnimatedView.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()), + ROUNDED_CORNER_RADIUS * view.getWidth()); + } + }); + mScreenshotPreview = mScreenshotLayout.findViewById(R.id.global_screenshot_preview); + mScreenshotPreview.setClipToOutline(true); + mScreenshotPreview.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()), @@ -255,6 +261,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset } }); + mActionsContainerBackground = mScreenshotLayout.findViewById( + R.id.global_screenshot_actions_container_background); mActionsContainer = mScreenshotLayout.findViewById( R.id.global_screenshot_actions_container); mActionsView = mScreenshotLayout.findViewById(R.id.global_screenshot_actions); @@ -273,9 +281,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mScreenshotLayout.setFocusable(true); mScreenshotSelectorView.setFocusable(true); mScreenshotSelectorView.setFocusableInTouchMode(true); - mScreenshotView.setPivotX(0); - mScreenshotView.setPivotY(0); - mActionsContainer.setPivotX(0); + mScreenshotAnimatedView.setPivotX(0); + mScreenshotAnimatedView.setPivotY(0); // Setup the window that we are going to use mWindowLayoutParams = new WindowManager.LayoutParams( @@ -297,10 +304,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mScreenshotOffsetXPx = resources.getDimensionPixelSize(R.dimen.screenshot_offset_x); mScreenshotOffsetYPx = resources.getDimensionPixelSize(R.dimen.screenshot_offset_y); - mScreenshotHeightPx = - resources.getDimensionPixelSize(R.dimen.screenshot_action_container_offset_y); - mDismissButtonSize = resources.getDimensionPixelSize( - R.dimen.screenshot_dismiss_button_tappable_size); mCornerSizeX = resources.getDimensionPixelSize(R.dimen.global_screenshot_x_scale); mDismissDeltaY = resources.getDimensionPixelSize(R.dimen.screenshot_dismissal_height_delta); @@ -318,7 +321,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset Region touchRegion = new Region(); Rect screenshotRect = new Rect(); - mScreenshotView.getBoundsOnScreen(screenshotRect); + mScreenshotPreview.getBoundsOnScreen(screenshotRect); touchRegion.op(screenshotRect, Region.Op.UNION); Rect actionsRect = new Rect(); mActionsContainer.getBoundsOnScreen(actionsRect); @@ -469,6 +472,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset */ private void dismissScreenshot(String reason, boolean immediate) { Log.v(TAG, "clearing screenshot: " + reason); + mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT); + mScreenshotLayout.getViewTreeObserver().removeOnComputeInternalInsetsListener(this); if (!immediate) { mDismissAnimation = createScreenshotDismissAnimation(); mDismissAnimation.addListener(new AnimatorListenerAdapter() { @@ -488,23 +493,23 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset if (mScreenshotLayout.isAttachedToWindow()) { mWindowManager.removeView(mScreenshotLayout); } - mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT); - mScreenshotLayout.getViewTreeObserver().removeOnComputeInternalInsetsListener(this); // Clear any references to the bitmap - mScreenshotView.setImageBitmap(null); + mScreenshotPreview.setImageBitmap(null); + mScreenshotAnimatedView.setImageBitmap(null); + mActionsContainerBackground.setVisibility(View.GONE); mActionsContainer.setVisibility(View.GONE); - mBackgroundView.setVisibility(View.GONE); mBackgroundProtection.setAlpha(0f); mDismissButton.setVisibility(View.GONE); - mScreenshotView.setVisibility(View.GONE); - mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null); - mScreenshotView.setContentDescription( + mScreenshotPreview.setVisibility(View.GONE); + mScreenshotPreview.setLayerType(View.LAYER_TYPE_NONE, null); + mScreenshotPreview.setContentDescription( mContext.getResources().getString(R.string.screenshot_preview_description)); mScreenshotLayout.setAlpha(1); mDismissButton.setTranslationY(0); mActionsContainer.setTranslationY(0); - mScreenshotView.setTranslationY(0); + mActionsContainerBackground.setTranslationY(0); + mScreenshotPreview.setTranslationY(0); } /** @@ -514,9 +519,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset */ private void reloadAssets() { mDismissImage.setImageDrawable(mContext.getDrawable(R.drawable.screenshot_cancel)); - mActionsContainer.setBackground( + mActionsContainerBackground.setBackground( mContext.getDrawable(R.drawable.action_chip_container_background)); - } /** @@ -558,10 +562,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset Toast.LENGTH_SHORT).show(); } - - // Add the view for the animation - mScreenshotView.setImageBitmap(mScreenBitmap); - mScreenshotAnimation = createScreenshotDropInAnimation(w, h, screenRect); saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() { @@ -600,8 +600,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset // Play the shutter sound to notify that we've taken a screenshot mCameraSound.play(MediaActionSound.SHUTTER_CLICK); - mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null); - mScreenshotView.buildLayer(); + mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null); + mScreenshotPreview.buildLayer(); mScreenshotAnimation.start(); }); } @@ -609,6 +609,14 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private AnimatorSet createScreenshotDropInAnimation(int width, int height, Rect bounds) { float cornerScale = mCornerSizeX / (float) width; + mScreenshotAnimatedView.setScaleX(1); + mScreenshotAnimatedView.setScaleY(1); + mScreenshotAnimatedView.setX(0); + mScreenshotAnimatedView.setY(0); + + mScreenshotAnimatedView.setImageBitmap(mScreenBitmap); + mScreenshotPreview.setImageBitmap(mScreenBitmap); + AnimatorSet dropInAnimation = new AnimatorSet(); ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1); flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS); @@ -623,9 +631,16 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mScreenshotFlash.setAlpha((float) animation.getAnimatedValue())); final PointF startPos = new PointF(bounds.centerX(), bounds.centerY()); - final PointF finalPos = new PointF(mScreenshotOffsetXPx + width * cornerScale / 2f, - mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - - height * cornerScale / 2f); + float finalX; + if (mContext.getResources().getConfiguration().getLayoutDirection() + == View.LAYOUT_DIRECTION_LTR) { + finalX = mScreenshotOffsetXPx + width * cornerScale / 2f; + } else { + finalX = width - mScreenshotOffsetXPx - width * cornerScale / 2f; + } + float finalY = + mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale / 2f; + final PointF finalPos = new PointF(finalX, finalY); ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1); toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS); @@ -639,30 +654,33 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset if (t < scalePct) { float scale = MathUtils.lerp( 1, cornerScale, mFastOutSlowIn.getInterpolation(t / scalePct)); - mScreenshotView.setScaleX(scale); - mScreenshotView.setScaleY(scale); + mScreenshotAnimatedView.setScaleX(scale); + mScreenshotAnimatedView.setScaleY(scale); } else { - mScreenshotView.setScaleX(cornerScale); - mScreenshotView.setScaleY(cornerScale); + mScreenshotAnimatedView.setScaleX(cornerScale); + mScreenshotAnimatedView.setScaleY(cornerScale); } + float currentScaleX = mScreenshotAnimatedView.getScaleX(); + float currentScaleY = mScreenshotAnimatedView.getScaleY(); + if (t < xPositionPct) { float xCenter = MathUtils.lerp(startPos.x, finalPos.x, mFastOutSlowIn.getInterpolation(t / xPositionPct)); - mScreenshotView.setX(xCenter - width * mScreenshotView.getScaleX() / 2f); + mScreenshotAnimatedView.setX(xCenter - width * currentScaleX / 2f); } else { - mScreenshotView.setX(finalPos.x - width * mScreenshotView.getScaleX() / 2f); + mScreenshotAnimatedView.setX(finalPos.x - width * currentScaleX / 2f); } float yCenter = MathUtils.lerp(startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t)); - mScreenshotView.setY(yCenter - height * mScreenshotView.getScaleY() / 2f); + mScreenshotAnimatedView.setY(yCenter - height * currentScaleY / 2f); }); toCorner.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); - mScreenshotView.setVisibility(View.VISIBLE); + mScreenshotAnimatedView.setVisibility(View.VISIBLE); } }); @@ -676,15 +694,16 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mScreenshotView.setScaleX(cornerScale); - mScreenshotView.setScaleY(cornerScale); - mScreenshotView.setX(finalPos.x - width * cornerScale / 2f); - mScreenshotView.setY(finalPos.y - height * cornerScale / 2f); + mScreenshotAnimatedView.setScaleX(1); + mScreenshotAnimatedView.setScaleY(1); + mScreenshotAnimatedView.setX(finalPos.x - width * cornerScale / 2f); + mScreenshotAnimatedView.setY(finalPos.y - height * cornerScale / 2f); Rect bounds = new Rect(); - mScreenshotView.getBoundsOnScreen(bounds); - mDismissButton.setX(bounds.right - mDismissButtonSize / 2f); - mDismissButton.setY(bounds.top - mDismissButtonSize / 2f); + mDismissButton.getBoundsOnScreen(bounds); + mScreenshotAnimatedView.setVisibility(View.GONE); + mScreenshotPreview.setVisibility(View.VISIBLE); mDismissButton.setVisibility(View.VISIBLE); + mScreenshotLayout.forceLayout(); } }); @@ -747,7 +766,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mActionsView.addView(editChip); chips.add(editChip); - mScreenshotView.setOnClickListener(v -> { + mScreenshotPreview.setOnClickListener(v -> { try { imageData.editAction.actionIntent.send(); mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED); @@ -757,7 +776,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset Log.e(TAG, "Intent cancelled", e); } }); - mScreenshotView.setContentDescription(imageData.editAction.title); + mScreenshotPreview.setContentDescription(imageData.editAction.title); if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SCREENSHOT_SCROLLING_ENABLED, false)) { ScreenshotActionChip scrollChip = (ScreenshotActionChip) inflater.inflate( @@ -775,20 +794,33 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset chips.add(scrollChip); } + // remove the margin from the last chip so that it's correctly aligned with the end + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) + mActionsView.getChildAt(mActionsView.getChildCount() - 1).getLayoutParams(); + params.setMarginEnd(0); + ValueAnimator animator = ValueAnimator.ofFloat(0, 1); animator.setDuration(SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS); float alphaFraction = (float) SCREENSHOT_ACTIONS_ALPHA_DURATION_MS / SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS; - mActionsContainer.setVisibility(VISIBLE); - mActionsContainer.setAlpha(0); + mActionsContainer.setVisibility(View.VISIBLE); + mActionsContainer.setAlpha(0f); + mActionsContainerBackground.setAlpha(0f); + mActionsContainerBackground.setVisibility(View.VISIBLE); + + mActionsContainer.setPivotX(0); + mActionsContainerBackground.setPivotX(0); animator.addUpdateListener(animation -> { float t = animation.getAnimatedFraction(); mBackgroundProtection.setAlpha(t); - mActionsContainer.setAlpha(t < alphaFraction ? t / alphaFraction : 1); + float containerAlpha = t < alphaFraction ? t / alphaFraction : 1; + mActionsContainer.setAlpha(containerAlpha); + mActionsContainerBackground.setAlpha(containerAlpha); float containerScale = SCREENSHOT_ACTIONS_START_SCALE_X + (t * (1 - SCREENSHOT_ACTIONS_START_SCALE_X)); mActionsContainer.setScaleX(containerScale); + mActionsContainerBackground.setScaleX(containerScale); for (ScreenshotActionChip chip : chips) { chip.setAlpha(t); chip.setScaleX(1 / containerScale); // invert to keep size of children constant @@ -808,13 +840,14 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1); yAnim.setInterpolator(mAccelerateInterpolator); yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS); - float screenshotStartY = mScreenshotView.getTranslationY(); + float screenshotStartY = mScreenshotPreview.getTranslationY(); float dismissStartY = mDismissButton.getTranslationY(); yAnim.addUpdateListener(animation -> { float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction()); - mScreenshotView.setTranslationY(screenshotStartY + yDelta); + mScreenshotPreview.setTranslationY(screenshotStartY + yDelta); mDismissButton.setTranslationY(dismissStartY + yDelta); mActionsContainer.setTranslationY(yDelta); + mActionsContainerBackground.setTranslationY(yDelta); }); AnimatorSet animSet = new AnimatorSet();