Android系统截屏功能提取

简介:

http://blog.csdn.net/xu_fu/article/details/39268771

Android在4.0版本之后同时按电源键和音量键可以截取当前屏幕,截图后会有一个过渡动画效果,这里提取了将效果这部分提取出来,可以用于应用截图分享功能。

截图功能在源码中的位置是com.android.systemui.screenshot,下面有四个类


其中主要工作都在GlobalScreenshot中,包括截图后的动画效果、保存到本地和显示到通知栏。为了简单,下面的代码只保留了过渡动画部分

  1. class GlobalScreenshot {  
  2.     private static final String TAG = "GlobalScreenshot";  
  3.   
  4.     private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;  
  5.     private static final int SCREENSHOT_DROP_IN_DURATION = 430;  
  6.     private static final int SCREENSHOT_DROP_OUT_DELAY = 500;  
  7.     private static final int SCREENSHOT_DROP_OUT_DURATION = 430;  
  8.     private static final int SCREENSHOT_DROP_OUT_SCALE_DURATION = 370;  
  9.     private static final int SCREENSHOT_FAST_DROP_OUT_DURATION = 320;  
  10.     private static final float BACKGROUND_ALPHA = 0.5f;  
  11.     private static final float SCREENSHOT_SCALE = 1f;  
  12.     private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f;  
  13.     private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f;  
  14.     private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f;  
  15.     private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;  
  16.   
  17.     private Context mContext;  
  18.     private WindowManager mWindowManager;  
  19.     private WindowManager.LayoutParams mWindowLayoutParams;  
  20.     private Display mDisplay;  
  21.     private DisplayMetrics mDisplayMetrics;  
  22.   
  23.     private Bitmap mScreenBitmap;  
  24.     private View mScreenshotLayout;  
  25.     private ImageView mBackgroundView;  
  26.     private ImageView mScreenshotView;  
  27.     private ImageView mScreenshotFlash;  
  28.   
  29.     private AnimatorSet mScreenshotAnimation;  
  30.   
  31.     private float mBgPadding;  
  32.     private float mBgPaddingScale;  
  33.   
  34.     private MediaActionSound mCameraSound;  
  35.   
  36.   
  37.     /** 
  38.      * @param context everything needs a context :( 
  39.      */  
  40.     public GlobalScreenshot(Context context) {  
  41.         Resources r = context.getResources();  
  42.         mContext = context;  
  43.         LayoutInflater layoutInflater = (LayoutInflater)  
  44.                 context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  45.   
  46.         // Inflate the screenshot layout   
  47.         mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);  
  48.         mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);  
  49.         mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);  
  50.         mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);  
  51.         mScreenshotLayout.setFocusable(true);  
  52.         mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {  
  53.             @Override  
  54.             public boolean onTouch(View v, MotionEvent event) {  
  55.                 // Intercept and ignore all touch events   
  56.                 return true;  
  57.             }  
  58.         });  
  59.   
  60.         // Setup the window that we are going to use   
  61.         mWindowLayoutParams = new WindowManager.LayoutParams(  
  62.                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 00,  
  63.                 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,  
  64.                 WindowManager.LayoutParams.FLAG_FULLSCREEN  
  65.                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED  
  66.                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN  
  67.                         | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,  
  68.                 PixelFormat.TRANSLUCENT);  
  69.         mWindowLayoutParams.setTitle("ScreenshotAnimation");  
  70.         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);  
  71.   
  72.         mDisplay = mWindowManager.getDefaultDisplay();  
  73.         mDisplayMetrics = new DisplayMetrics();  
  74.         mDisplay.getRealMetrics(mDisplayMetrics);  
  75.   
  76.         // Scale has to account for both sides of the bg   
  77.         mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);  
  78.         mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;  
  79.   
  80.         // Setup the Camera shutter sound   
  81.         mCameraSound = new MediaActionSound();  
  82.         mCameraSound.load(MediaActionSound.SHUTTER_CLICK);  
  83.     }  
  84.   
  85.   
  86.   
  87.     /** 
  88.      * Takes a screenshot of the current display and shows an animation. 
  89.      */  
  90.     void takeScreenshot(View view, Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {  
  91.         // Take the screenshot   
  92.         mScreenBitmap = SurfaceControl.screenshot(view);  
  93.         if (mScreenBitmap == null) {  
  94.             notifyScreenshotError(mContext);  
  95.             finisher.run();  
  96.             return;  
  97.         }  
  98.   
  99.         // Optimizations   
  100.         mScreenBitmap.setHasAlpha(false);  
  101.         mScreenBitmap.prepareToDraw();  
  102.   
  103.         // Start the post-screenshot animation   
  104.         startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,  
  105.                 statusBarVisible, navBarVisible);  
  106.     }  
  107.   
  108.   
  109.     /** 
  110.      * Starts the animation after taking the screenshot 
  111.      */  
  112.     private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible,  
  113.                                 boolean navBarVisible) {  
  114.         // Add the view for the animation   
  115.         mScreenshotView.setImageBitmap(mScreenBitmap);  
  116.         mScreenshotLayout.requestFocus();  
  117.   
  118.         // Setup the animation with the screenshot just taken   
  119.         if (mScreenshotAnimation != null) {  
  120.             mScreenshotAnimation.end();  
  121.             mScreenshotAnimation.removeAllListeners();  
  122.         }  
  123.   
  124.         mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);  
  125.         ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();  
  126.         ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,  
  127.                 statusBarVisible, navBarVisible);  
  128.         mScreenshotAnimation = new AnimatorSet();  
  129.         mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);  
  130.         mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {  
  131.             @Override  
  132.             public void onAnimationEnd(Animator animation) {  
  133.                 // Save the screenshot once we have a bit of time now   
  134.                 saveScreenshotInWorkerThread(finisher);  
  135.                 mWindowManager.removeView(mScreenshotLayout);  
  136.   
  137.                 // Clear any references to the bitmap   
  138.                 mScreenBitmap = null;  
  139.                 mScreenshotView.setImageBitmap(null);  
  140.             }  
  141.         });  
  142.         mScreenshotLayout.post(new Runnable() {  
  143.             @Override  
  144.             public void run() {  
  145.                 // Play the shutter sound to notify that we've taken a screenshot   
  146.                 mCameraSound.play(MediaActionSound.SHUTTER_CLICK);  
  147.   
  148.                 mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);  
  149.                 mScreenshotView.buildLayer();  
  150.                 mScreenshotAnimation.start();  
  151.             }  
  152.         });  
  153.     }  
  154.   
  155.     private ValueAnimator createScreenshotDropInAnimation() {  
  156.         final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)  
  157.                 / SCREENSHOT_DROP_IN_DURATION);  
  158.         final float flashDurationPct = 2f * flashPeakDurationPct;  
  159.         final Interpolator flashAlphaInterpolator = new Interpolator() {  
  160.             @Override  
  161.             public float getInterpolation(float x) {  
  162.                 // Flash the flash view in and out quickly   
  163.                 if (x <= flashDurationPct) {  
  164.                     return (float) Math.sin(Math.PI * (x / flashDurationPct));  
  165.                 }  
  166.                 return 0;  
  167.             }  
  168.         };  
  169.         final Interpolator scaleInterpolator = new Interpolator() {  
  170.             @Override  
  171.             public float getInterpolation(float x) {  
  172.                 // We start scaling when the flash is at it's peak   
  173.                 if (x < flashPeakDurationPct) {  
  174.                     return 0;  
  175.                 }  
  176.                 return (x - flashDurationPct) / (1f - flashDurationPct);  
  177.             }  
  178.         };  
  179.         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
  180.         anim.setDuration(SCREENSHOT_DROP_IN_DURATION);  
  181.         anim.addListener(new AnimatorListenerAdapter() {  
  182.             @Override  
  183.             public void onAnimationStart(Animator animation) {  
  184.                 mBackgroundView.setAlpha(0f);  
  185.                 mBackgroundView.setVisibility(View.VISIBLE);  
  186.                 mScreenshotView.setAlpha(0f);  
  187.                 mScreenshotView.setTranslationX(0f);  
  188.                 mScreenshotView.setTranslationY(0f);  
  189.                 mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);  
  190.                 mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);  
  191.                 mScreenshotView.setVisibility(View.VISIBLE);  
  192.                 mScreenshotFlash.setAlpha(0f);  
  193.                 mScreenshotFlash.setVisibility(View.VISIBLE);  
  194.             }  
  195.   
  196.             @Override  
  197.             public void onAnimationEnd(android.animation.Animator animation) {  
  198.                 mScreenshotFlash.setVisibility(View.GONE);  
  199.             }  
  200.         });  
  201.         anim.addUpdateListener(new AnimatorUpdateListener() {  
  202.             @Override  
  203.             public void onAnimationUpdate(ValueAnimator animation) {  
  204.                 float t = (Float) animation.getAnimatedValue();  
  205.                 float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)  
  206.                         - scaleInterpolator.getInterpolation(t)  
  207.                         * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);  
  208.                 mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);  
  209.                 mScreenshotView.setAlpha(t);  
  210.                 mScreenshotView.setScaleX(scaleT);  
  211.                 mScreenshotView.setScaleY(scaleT);  
  212.                 mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t));  
  213.             }  
  214.         });  
  215.         return anim;  
  216.     }  
  217.   
  218.     private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,  
  219.                                                            boolean navBarVisible) {  
  220.         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
  221.         anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);  
  222.         anim.addListener(new AnimatorListenerAdapter() {  
  223.             @Override  
  224.             public void onAnimationEnd(Animator animation) {  
  225.                 mBackgroundView.setVisibility(View.GONE);  
  226.                 mScreenshotView.setVisibility(View.GONE);  
  227.                 mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);  
  228.             }  
  229.         });  
  230.   
  231.         if (!statusBarVisible || !navBarVisible) {  
  232.             // There is no status bar/nav bar, so just fade the screenshot away in place   
  233.             anim.setDuration(SCREENSHOT_FAST_DROP_OUT_DURATION);  
  234.             anim.addUpdateListener(new AnimatorUpdateListener() {  
  235.                 @Override  
  236.                 public void onAnimationUpdate(ValueAnimator animation) {  
  237.                     float t = (Float) animation.getAnimatedValue();  
  238.                     float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)  
  239.                             - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);  
  240.                     mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);  
  241.                     mScreenshotView.setAlpha(1f - t);  
  242.                     mScreenshotView.setScaleX(scaleT);  
  243.                     mScreenshotView.setScaleY(scaleT);  
  244.                 }  
  245.             });  
  246.         } else {  
  247.             // In the case where there is a status bar, animate to the origin of the bar (top-left)   
  248.             final float scaleDurationPct = (float) SCREENSHOT_DROP_OUT_SCALE_DURATION  
  249.                     / SCREENSHOT_DROP_OUT_DURATION;  
  250.             final Interpolator scaleInterpolator = new Interpolator() {  
  251.                 @Override  
  252.                 public float getInterpolation(float x) {  
  253.                     if (x < scaleDurationPct) {  
  254.                         // Decelerate, and scale the input accordingly   
  255.                         return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f));  
  256.                     }  
  257.                     return 1f;  
  258.                 }  
  259.             };  
  260.   
  261.             // Determine the bounds of how to scale   
  262.             float halfScreenWidth = (w - 2f * mBgPadding) / 2f;  
  263.             float halfScreenHeight = (h - 2f * mBgPadding) / 2f;  
  264.             final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;  
  265.             final PointF finalPos = new PointF(  
  266.                     -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,  
  267.                     -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);  
  268.   
  269.             // Animate the screenshot to the status bar   
  270.             anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);  
  271.             anim.addUpdateListener(new AnimatorUpdateListener() {  
  272.                 @Override  
  273.                 public void onAnimationUpdate(ValueAnimator animation) {  
  274.                     float t = (Float) animation.getAnimatedValue();  
  275.                     float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)  
  276.                             - scaleInterpolator.getInterpolation(t)  
  277.                             * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);  
  278.                     mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);  
  279.                     mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));  
  280.                     mScreenshotView.setScaleX(scaleT);  
  281.                     mScreenshotView.setScaleY(scaleT);  
  282.                     mScreenshotView.setTranslationX(t * finalPos.x);  
  283.                     mScreenshotView.setTranslationY(t * finalPos.y);  
  284.                 }  
  285.             });  
  286.         }  
  287.         return anim;  
  288.     }  
  289.   
  290.     private void notifyScreenshotError(Context context) {  
  291.   
  292.     }  
  293.   
  294.     private void saveScreenshotInWorkerThread(Runnable runnable) {  
  295.   
  296.     }  
  297.   
  298.   
  299. }  

看一下效果


下面是下面就分析一下相关原理:

1、截图如何显示

截图后返回对应的bitmap,用WindowManager直接在屏幕上将bitmap显示出来,也就是将bitmap放到一个imageView中,WindowManager addview就可以显示了。

为了有阴影的效果,这里额外定义了一个layout:global_screenshot.xml,如下

  1. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent">  
  4.     <ImageView android:id="@+id/global_screenshot_background"  
  5.         android:layout_width="match_parent"  
  6.         android:layout_height="match_parent"  
  7.         android:src="@android:color/black"  
  8.         android:visibility="gone" />  
  9.     <ImageView android:id="@+id/global_screenshot"  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content"  
  12.         android:layout_gravity="center"  
  13.         android:background="@drawable/screenshot_panel"  
  14.         android:visibility="gone"  
  15.         android:adjustViewBounds="true" />  
  16.     <ImageView android:id="@+id/global_screenshot_flash"  
  17.         android:layout_width="match_parent"  
  18.         android:layout_height="match_parent"  
  19.         android:src="@android:color/white"  
  20.         android:visibility="gone" />  
  21. </FrameLayout>  

上面的布局一共有三层,最下面的background用于遮盖,中间的screenshot用于放截图,最上边还有一层flash,主要是用于做一个反光的效果。

截图的bitmap就放在global_screenshot这个imageview中。对应的代码

  1. mScreenshotView.setImageBitmap(mScreenBitmap);  
  2.         mScreenshotLayout.requestFocus();  
  3.   
  4.         // Setup the animation with the screenshot just taken   
  5.         if (mScreenshotAnimation != null) {  
  6.             mScreenshotAnimation.end();  
  7.             mScreenshotAnimation.removeAllListeners();  
  8.         }  
  9.   
  10.         mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);  

这样就可以在屏幕上看到截图了,之后还有一个过渡动画效果,分别是

  1. ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();  
  2. ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,  
  3.         statusBarVisible, navBarVisible);  

这两个属性动画完成了显示-缩放-消失这个过程,具体就是对上面三层view进行变换了。

在Activity中调用

  1. protected void onCreate(Bundle savedInstanceState) {  
  2.         super.onCreate(savedInstanceState);  
  3.         setContentView(R.layout.activity_main);  
  4.   
  5.         final GlobalScreenshot screenshot = new GlobalScreenshot(this);  
  6.         findViewById(R.id.main_btn).setOnClickListener(new View.OnClickListener() {  
  7.             @Override  
  8.             public void onClick(View v) {  
  9.                 screenshot.takeScreenshot(getWindow().getDecorView(), new Runnable() {  
  10.                     @Override  
  11.                     public void run() {  
  12.   
  13.                     }  
  14.                 }, truetrue);  
  15.             }  
  16.         });  
  17.     }  

后面的两个boolean参数是表示是否有状态栏,用于显示不同的淡出动画,如果有一个为false,就会直接淡出,而不会向上偏移到状态栏上。

示例代码->http://download.csdn.net/detail/xu_fu/7921645

相关文章
|
1月前
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
1月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
21天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
23天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
1月前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
69 16
|
28天前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
1月前
|
算法 JavaScript Android开发
|
Java Android开发 开发者
Android 悬浮窗功能的实现
Android 悬浮窗功能的实现
1414 2
|
Android开发 容器 数据格式
Android 购物车功能的实现
首先,众所周知,ListView是Android最常用的控件,可以说是最简单的控件,也可以说是最复杂的控件。 作为一个Android初级开发者,可能会简单的ListView展示图文信息。 作为一个有一定项目开发经验的Android开发者来说,可能会遇到ListView的列表项中存在各种按钮的需求。
1176 0