3434import android .graphics .Matrix ;
3535import android .graphics .PixelFormat ;
3636import android .graphics .PointF ;
37- import android .graphics .RectF ;
3837import android .net .Uri ;
3938import android .os .AsyncTask ;
4039import android .os .Environment ;
5251import android .view .WindowManager ;
5352import android .view .animation .AccelerateInterpolator ;
5453import android .view .animation .DecelerateInterpolator ;
54+ import android .view .animation .Interpolator ;
5555import android .widget .FrameLayout ;
5656import android .widget .ImageView ;
5757
@@ -229,15 +229,18 @@ protected void onPostExecute(SaveImageInBackgroundData params) {
229229class GlobalScreenshot {
230230 private static final String TAG = "GlobalScreenshot" ;
231231 private static final int SCREENSHOT_NOTIFICATION_ID = 789 ;
232- private static final int SCREENSHOT_FADE_IN_DURATION = 250 ;
233- private static final int SCREENSHOT_FADE_OUT_DELAY = 750 ;
234- private static final int SCREENSHOT_FADE_OUT_DURATION = 500 ;
235- private static final int SCREENSHOT_FAST_FADE_OUT_DURATION = 350 ;
236- private static final float BACKGROUND_ALPHA = 0.65f ;
237- private static final float SCREENSHOT_SCALE_FUDGE = 0.075f ; // To account for the border padding
238- private static final float SCREENSHOT_SCALE = 0.55f ;
239- private static final float SCREENSHOT_FADE_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.975f ;
240- private static final float SCREENSHOT_FADE_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.925f ;
232+ private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130 ;
233+ private static final int SCREENSHOT_DROP_IN_DURATION = 430 ;
234+ private static final int SCREENSHOT_DROP_OUT_DELAY = 500 ;
235+ private static final int SCREENSHOT_DROP_OUT_DURATION = 430 ;
236+ private static final int SCREENSHOT_DROP_OUT_SCALE_DURATION = 370 ;
237+ private static final int SCREENSHOT_FAST_DROP_OUT_DURATION = 320 ;
238+ private static final float BACKGROUND_ALPHA = 0.5f ;
239+ private static final float SCREENSHOT_SCALE = 1f ;
240+ private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f ;
241+ private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f ;
242+ private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f ;
243+ private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f ;
241244
242245 private Context mContext ;
243246 private LayoutInflater mLayoutInflater ;
@@ -254,13 +257,11 @@ class GlobalScreenshot {
254257 private ImageView mBackgroundView ;
255258 private FrameLayout mScreenshotContainerView ;
256259 private ImageView mScreenshotView ;
260+ private ImageView mScreenshotFlash ;
257261
258262 private AnimatorSet mScreenshotAnimation ;
259263
260- private int mStatusBarIconSize ;
261264 private int mNotificationIconSize ;
262- private float mDropOffsetX ;
263- private float mDropOffsetY ;
264265 private float mBgPadding ;
265266 private float mBgPaddingScale ;
266267
@@ -280,6 +281,7 @@ public GlobalScreenshot(Context context) {
280281 mBackgroundView = (ImageView ) mScreenshotLayout .findViewById (R .id .global_screenshot_background );
281282 mScreenshotContainerView = (FrameLayout ) mScreenshotLayout .findViewById (R .id .global_screenshot_container );
282283 mScreenshotView = (ImageView ) mScreenshotLayout .findViewById (R .id .global_screenshot );
284+ mScreenshotFlash = (ImageView ) mScreenshotLayout .findViewById (R .id .global_screenshot_flash );
283285 mScreenshotLayout .setFocusable (true );
284286 mScreenshotLayout .setOnTouchListener (new View .OnTouchListener () {
285287 @ Override
@@ -309,16 +311,12 @@ public boolean onTouch(View v, MotionEvent event) {
309311 mDisplay .getRealMetrics (mDisplayMetrics );
310312
311313 // Get the various target sizes
312- mStatusBarIconSize =
313- r .getDimensionPixelSize (com .android .internal .R .dimen .status_bar_icon_size );
314314 mNotificationIconSize =
315315 r .getDimensionPixelSize (android .R .dimen .notification_large_icon_height );
316- mDropOffsetX = r .getDimensionPixelSize (R .dimen .global_screenshot_drop_offset_x );
317- mDropOffsetY = r .getDimensionPixelSize (R .dimen .global_screenshot_drop_offset_y );
318316
319317 // Scale has to account for both sides of the bg
320318 mBgPadding = (float ) r .getDimensionPixelSize (R .dimen .global_screenshot_bg_padding );
321- mBgPaddingScale = ( 2f * mBgPadding ) / mDisplayMetrics .widthPixels ;
319+ mBgPaddingScale = mBgPadding / mDisplayMetrics .widthPixels ;
322320 }
323321
324322 /**
@@ -413,11 +411,11 @@ private void startAnimation(final Runnable finisher, int w, int h, boolean statu
413411 }
414412
415413 mWindowManager .addView (mScreenshotLayout , mWindowLayoutParams );
416- ValueAnimator screenshotFadeInAnim = createScreenshotFadeInAnimation ();
417- ValueAnimator screenshotFadeOutAnim = createScreenshotFadeOutAnimation (w , h ,
414+ ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation ();
415+ ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation (w , h ,
418416 statusBarVisible , navBarVisible );
419417 mScreenshotAnimation = new AnimatorSet ();
420- mScreenshotAnimation .play ( screenshotFadeInAnim ). before ( screenshotFadeOutAnim );
418+ mScreenshotAnimation .playSequentially ( screenshotDropInAnim , screenshotFadeOutAnim );
421419 mScreenshotAnimation .addListener (new AnimatorListenerAdapter () {
422420 @ Override
423421 public void onAnimationEnd (Animator animation ) {
@@ -435,42 +433,71 @@ public void run() {
435433 }
436434 });
437435 }
438- private ValueAnimator createScreenshotFadeInAnimation () {
436+ private ValueAnimator createScreenshotDropInAnimation () {
437+ final float flashPeakDurationPct = ((float ) (SCREENSHOT_FLASH_TO_PEAK_DURATION )
438+ / SCREENSHOT_DROP_IN_DURATION );
439+ final float flashDurationPct = 2f * flashPeakDurationPct ;
440+ final Interpolator flashAlphaInterpolator = new Interpolator () {
441+ @ Override
442+ public float getInterpolation (float x ) {
443+ // Flash the flash view in and out quickly
444+ if (x <= flashDurationPct ) {
445+ return (float ) Math .sin (Math .PI * (x / flashDurationPct ));
446+ }
447+ return 0 ;
448+ }
449+ };
450+ final Interpolator scaleInterpolator = new Interpolator () {
451+ @ Override
452+ public float getInterpolation (float x ) {
453+ // We start scaling when the flash is at it's peak
454+ if (x < flashPeakDurationPct ) {
455+ return 0 ;
456+ }
457+ return (x - flashDurationPct ) / (1f - flashDurationPct );
458+ }
459+ };
439460 ValueAnimator anim = ValueAnimator .ofFloat (0f , 1f );
440- anim .setInterpolator (new AccelerateInterpolator (1.5f ));
441- anim .setDuration (SCREENSHOT_FADE_IN_DURATION );
461+ anim .setDuration (SCREENSHOT_DROP_IN_DURATION );
442462 anim .addListener (new AnimatorListenerAdapter () {
443463 @ Override
444464 public void onAnimationStart (Animator animation ) {
445465 mBackgroundView .setAlpha (0f );
446466 mBackgroundView .setVisibility (View .VISIBLE );
467+ mScreenshotContainerView .setAlpha (0f );
447468 mScreenshotContainerView .setTranslationX (0f );
448469 mScreenshotContainerView .setTranslationY (0f );
449- mScreenshotContainerView .setScaleX (SCREENSHOT_FADE_IN_MIN_SCALE );
450- mScreenshotContainerView .setScaleY (SCREENSHOT_FADE_IN_MIN_SCALE );
451- mScreenshotContainerView .setAlpha (0f );
470+ mScreenshotContainerView .setScaleX (SCREENSHOT_SCALE + mBgPaddingScale );
471+ mScreenshotContainerView .setScaleY (SCREENSHOT_SCALE + mBgPaddingScale );
452472 mScreenshotContainerView .setVisibility (View .VISIBLE );
473+ mScreenshotFlash .setAlpha (0f );
474+ mScreenshotFlash .setVisibility (View .VISIBLE );
475+ }
476+ @ Override
477+ public void onAnimationEnd (android .animation .Animator animation ) {
478+ mScreenshotFlash .setVisibility (View .GONE );
453479 }
454480 });
455481 anim .addUpdateListener (new AnimatorUpdateListener () {
456482 @ Override
457483 public void onAnimationUpdate (ValueAnimator animation ) {
458484 float t = ((Float ) animation .getAnimatedValue ()).floatValue ();
459- float scaleT = (SCREENSHOT_FADE_IN_MIN_SCALE )
460- + (float ) t * (SCREENSHOT_SCALE - SCREENSHOT_FADE_IN_MIN_SCALE );
461- mBackgroundView .setAlpha (t * BACKGROUND_ALPHA );
485+ float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale )
486+ - (float ) scaleInterpolator .getInterpolation (t )
487+ * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE );
488+ mBackgroundView .setAlpha (scaleInterpolator .getInterpolation (t ) * BACKGROUND_ALPHA );
489+ mScreenshotContainerView .setAlpha (t );
462490 mScreenshotContainerView .setScaleX (scaleT );
463491 mScreenshotContainerView .setScaleY (scaleT );
464- mScreenshotContainerView .setAlpha (t );
492+ mScreenshotFlash .setAlpha (flashAlphaInterpolator . getInterpolation ( t ) );
465493 }
466494 });
467495 return anim ;
468496 }
469- private ValueAnimator createScreenshotFadeOutAnimation (int w , int h , boolean statusBarVisible ,
497+ private ValueAnimator createScreenshotDropOutAnimation (int w , int h , boolean statusBarVisible ,
470498 boolean navBarVisible ) {
471499 ValueAnimator anim = ValueAnimator .ofFloat (0f , 1f );
472- anim .setInterpolator (new DecelerateInterpolator (0.5f ));
473- anim .setStartDelay (SCREENSHOT_FADE_OUT_DELAY );
500+ anim .setStartDelay (SCREENSHOT_DROP_OUT_DELAY );
474501 anim .addListener (new AnimatorListenerAdapter () {
475502 @ Override
476503 public void onAnimationEnd (Animator animation ) {
@@ -482,54 +509,58 @@ public void onAnimationEnd(Animator animation) {
482509
483510 if (!statusBarVisible || !navBarVisible ) {
484511 // There is no status bar/nav bar, so just fade the screenshot away in place
485- anim .setDuration (SCREENSHOT_FAST_FADE_OUT_DURATION );
512+ anim .setDuration (SCREENSHOT_FAST_DROP_OUT_DURATION );
486513 anim .addUpdateListener (new AnimatorUpdateListener () {
487514 @ Override
488515 public void onAnimationUpdate (ValueAnimator animation ) {
489516 float t = ((Float ) animation .getAnimatedValue ()).floatValue ();
490- float scaleT = (SCREENSHOT_FADE_OUT_MIN_SCALE )
491- + (float ) (1f - t ) * (SCREENSHOT_SCALE - SCREENSHOT_FADE_OUT_MIN_SCALE );
517+ float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale )
518+ - (float ) t * (SCREENSHOT_DROP_IN_MIN_SCALE
519+ - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE );
492520 mBackgroundView .setAlpha ((1f - t ) * BACKGROUND_ALPHA );
493- mScreenshotContainerView .setAlpha (( 1f - t ) * BACKGROUND_ALPHA );
521+ mScreenshotContainerView .setAlpha (1f - t );
494522 mScreenshotContainerView .setScaleX (scaleT );
495523 mScreenshotContainerView .setScaleY (scaleT );
496524 }
497525 });
498526 } else {
527+ // In the case where there is a status bar, animate to the origin of the bar (top-left)
528+ final float scaleDurationPct = (float ) SCREENSHOT_DROP_OUT_SCALE_DURATION
529+ / SCREENSHOT_DROP_OUT_DURATION ;
530+ final Interpolator scaleInterpolator = new Interpolator () {
531+ @ Override
532+ public float getInterpolation (float x ) {
533+ if (x < scaleDurationPct ) {
534+ // Decelerate, and scale the input accordingly
535+ return (float ) (1f - Math .pow (1f - (x / scaleDurationPct ), 2f ));
536+ }
537+ return 1f ;
538+ }
539+ };
540+
499541 // Determine the bounds of how to scale
500542 float halfScreenWidth = (w - 2f * mBgPadding ) / 2f ;
501543 float halfScreenHeight = (h - 2f * mBgPadding ) / 2f ;
502- final RectF finalBounds = new RectF (mDropOffsetX , mDropOffsetY ,
503- mDropOffsetX + mStatusBarIconSize ,
504- mDropOffsetY + mStatusBarIconSize );
505- final PointF currentPos = new PointF (0f , 0f );
506- final PointF finalPos = new PointF (-halfScreenWidth + finalBounds .centerX (),
507- -halfScreenHeight + finalBounds .centerY ());
508- final DecelerateInterpolator d = new DecelerateInterpolator (2f );
509- // Note: since the scale origin is in the center of the view, divide difference by 2
510- float tmpMinScale = 0f ;
511- if (w > h ) {
512- tmpMinScale = finalBounds .width () / (2f * w );
513- } else {
514- tmpMinScale = finalBounds .height () / (2f * h );
515- }
516- final float minScale = tmpMinScale ;
544+ final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET ;
545+ final PointF finalPos = new PointF (
546+ -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct ) * halfScreenWidth ,
547+ -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct ) * halfScreenHeight );
517548
518549 // Animate the screenshot to the status bar
519- anim .setDuration (SCREENSHOT_FADE_OUT_DURATION );
550+ anim .setDuration (SCREENSHOT_DROP_OUT_DURATION );
520551 anim .addUpdateListener (new AnimatorUpdateListener () {
521552 @ Override
522553 public void onAnimationUpdate (ValueAnimator animation ) {
523554 float t = ((Float ) animation .getAnimatedValue ()).floatValue ();
524- float scaleT = minScale
525- + (float ) (1f - t ) * (SCREENSHOT_SCALE - minScale - mBgPaddingScale )
526- + mBgPaddingScale ;
527- mScreenshotContainerView .setAlpha (d .getInterpolation (1f - t ));
528- mScreenshotContainerView .setTranslationX (d .getInterpolation (t ) * finalPos .x );
529- mScreenshotContainerView .setTranslationY (d .getInterpolation (t ) * finalPos .y );
555+ float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale )
556+ - (float ) scaleInterpolator .getInterpolation (t )
557+ * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE );
558+ mBackgroundView .setAlpha ((1f - t ) * BACKGROUND_ALPHA );
559+ mScreenshotContainerView .setAlpha (1f - scaleInterpolator .getInterpolation (t ));
530560 mScreenshotContainerView .setScaleX (scaleT );
531561 mScreenshotContainerView .setScaleY (scaleT );
532- mBackgroundView .setAlpha ((1f - t ) * BACKGROUND_ALPHA );
562+ mScreenshotContainerView .setTranslationX (t * finalPos .x );
563+ mScreenshotContainerView .setTranslationY (t * finalPos .y );
533564 }
534565 });
535566 }
0 commit comments