Android系统截屏功能提取

来源:互联网 发布:火淘宝的软件怎么样 编辑:程序博客网 时间:2024/05/16 01:04

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

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


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

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  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,如下

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  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中。对应的代码

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  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);  

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

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();  
  2. ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,  
  3.         statusBarVisible, navBarVisible);  

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

在Activity中调用

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  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

0 0
原创粉丝点击