Screenshot function extraction in Android system

Source: Internet
Author: User

Screenshot function extraction in Android system

Android 4.0 and later versions can capture the current screen by pressing the power key and volume key at the same time, and then there will be a transitional animation effect. Here we extract the effect, which can be used to apply the sharing function.

The function is located in the source code com. android. systemui. screenshot. There are four classes below


The main work is in GlobalScreenshot, including the animated effect, saved to the local device, and displayed in the notification bar. For simplicity, the following code only retains the transition animation part.

class GlobalScreenshot {    private static final String TAG = "GlobalScreenshot";    private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;    private static final int SCREENSHOT_DROP_IN_DURATION = 430;    private static final int SCREENSHOT_DROP_OUT_DELAY = 500;    private static final int SCREENSHOT_DROP_OUT_DURATION = 430;    private static final int SCREENSHOT_DROP_OUT_SCALE_DURATION = 370;    private static final int SCREENSHOT_FAST_DROP_OUT_DURATION = 320;    private static final float BACKGROUND_ALPHA = 0.5f;    private static final float SCREENSHOT_SCALE = 1f;    private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f;    private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f;    private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f;    private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;    private Context mContext;    private WindowManager mWindowManager;    private WindowManager.LayoutParams mWindowLayoutParams;    private Display mDisplay;    private DisplayMetrics mDisplayMetrics;    private Bitmap mScreenBitmap;    private View mScreenshotLayout;    private ImageView mBackgroundView;    private ImageView mScreenshotView;    private ImageView mScreenshotFlash;    private AnimatorSet mScreenshotAnimation;    private float mBgPadding;    private float mBgPaddingScale;    private MediaActionSound mCameraSound;    /**     * @param context everything needs a context :(     */    public GlobalScreenshot(Context context) {        Resources r = context.getResources();        mContext = context;        LayoutInflater layoutInflater = (LayoutInflater)                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        // Inflate the screenshot layout        mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);        mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);        mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);        mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);        mScreenshotLayout.setFocusable(true);        mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                // Intercept and ignore all touch events                return true;            }        });        // Setup the window that we are going to use        mWindowLayoutParams = new WindowManager.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,                WindowManager.LayoutParams.FLAG_FULLSCREEN                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,                PixelFormat.TRANSLUCENT);        mWindowLayoutParams.setTitle("ScreenshotAnimation");        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        mDisplay = mWindowManager.getDefaultDisplay();        mDisplayMetrics = new DisplayMetrics();        mDisplay.getRealMetrics(mDisplayMetrics);        // Scale has to account for both sides of the bg        mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);        mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;        // Setup the Camera shutter sound        mCameraSound = new MediaActionSound();        mCameraSound.load(MediaActionSound.SHUTTER_CLICK);    }    /**     * Takes a screenshot of the current display and shows an animation.     */    void takeScreenshot(View view, Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {        // Take the screenshot        mScreenBitmap = SurfaceControl.screenshot(view);        if (mScreenBitmap == null) {            notifyScreenshotError(mContext);            finisher.run();            return;        }        // Optimizations        mScreenBitmap.setHasAlpha(false);        mScreenBitmap.prepareToDraw();        // Start the post-screenshot animation        startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,                statusBarVisible, navBarVisible);    }    /**     * Starts the animation after taking the screenshot     */    private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible,                                boolean navBarVisible) {        // Add the view for the animation        mScreenshotView.setImageBitmap(mScreenBitmap);        mScreenshotLayout.requestFocus();        // Setup the animation with the screenshot just taken        if (mScreenshotAnimation != null) {            mScreenshotAnimation.end();            mScreenshotAnimation.removeAllListeners();        }        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);        ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();        ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,                statusBarVisible, navBarVisible);        mScreenshotAnimation = new AnimatorSet();        mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);        mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                // Save the screenshot once we have a bit of time now                saveScreenshotInWorkerThread(finisher);                mWindowManager.removeView(mScreenshotLayout);                // Clear any references to the bitmap                mScreenBitmap = null;                mScreenshotView.setImageBitmap(null);            }        });        mScreenshotLayout.post(new Runnable() {            @Override            public void run() {                // 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();                mScreenshotAnimation.start();            }        });    }    private ValueAnimator createScreenshotDropInAnimation() {        final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)                / SCREENSHOT_DROP_IN_DURATION);        final float flashDurationPct = 2f * flashPeakDurationPct;        final Interpolator flashAlphaInterpolator = new Interpolator() {            @Override            public float getInterpolation(float x) {                // Flash the flash view in and out quickly                if (x <= flashDurationPct) {                    return (float) Math.sin(Math.PI * (x / flashDurationPct));                }                return 0;            }        };        final Interpolator scaleInterpolator = new Interpolator() {            @Override            public float getInterpolation(float x) {                // We start scaling when the flash is at it's peak                if (x < flashPeakDurationPct) {                    return 0;                }                return (x - flashDurationPct) / (1f - flashDurationPct);            }        };        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);        anim.setDuration(SCREENSHOT_DROP_IN_DURATION);        anim.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationStart(Animator animation) {                mBackgroundView.setAlpha(0f);                mBackgroundView.setVisibility(View.VISIBLE);                mScreenshotView.setAlpha(0f);                mScreenshotView.setTranslationX(0f);                mScreenshotView.setTranslationY(0f);                mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);                mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);                mScreenshotView.setVisibility(View.VISIBLE);                mScreenshotFlash.setAlpha(0f);                mScreenshotFlash.setVisibility(View.VISIBLE);            }            @Override            public void onAnimationEnd(android.animation.Animator animation) {                mScreenshotFlash.setVisibility(View.GONE);            }        });        anim.addUpdateListener(new AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                float t = (Float) animation.getAnimatedValue();                float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)                        - scaleInterpolator.getInterpolation(t)                        * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);                mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);                mScreenshotView.setAlpha(t);                mScreenshotView.setScaleX(scaleT);                mScreenshotView.setScaleY(scaleT);                mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t));            }        });        return anim;    }    private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,                                                           boolean navBarVisible) {        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);        anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);        anim.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                mBackgroundView.setVisibility(View.GONE);                mScreenshotView.setVisibility(View.GONE);                mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);            }        });        if (!statusBarVisible || !navBarVisible) {            // There is no status bar/nav bar, so just fade the screenshot away in place            anim.setDuration(SCREENSHOT_FAST_DROP_OUT_DURATION);            anim.addUpdateListener(new AnimatorUpdateListener() {                @Override                public void onAnimationUpdate(ValueAnimator animation) {                    float t = (Float) animation.getAnimatedValue();                    float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)                            - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);                    mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);                    mScreenshotView.setAlpha(1f - t);                    mScreenshotView.setScaleX(scaleT);                    mScreenshotView.setScaleY(scaleT);                }            });        } else {            // In the case where there is a status bar, animate to the origin of the bar (top-left)            final float scaleDurationPct = (float) SCREENSHOT_DROP_OUT_SCALE_DURATION                    / SCREENSHOT_DROP_OUT_DURATION;            final Interpolator scaleInterpolator = new Interpolator() {                @Override                public float getInterpolation(float x) {                    if (x < scaleDurationPct) {                        // Decelerate, and scale the input accordingly                        return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f));                    }                    return 1f;                }            };            // Determine the bounds of how to scale            float halfScreenWidth = (w - 2f * mBgPadding) / 2f;            float halfScreenHeight = (h - 2f * mBgPadding) / 2f;            final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;            final PointF finalPos = new PointF(                    -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,                    -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);            // Animate the screenshot to the status bar            anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);            anim.addUpdateListener(new AnimatorUpdateListener() {                @Override                public void onAnimationUpdate(ValueAnimator animation) {                    float t = (Float) animation.getAnimatedValue();                    float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)                            - scaleInterpolator.getInterpolation(t)                            * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);                    mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);                    mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));                    mScreenshotView.setScaleX(scaleT);                    mScreenshotView.setScaleY(scaleT);                    mScreenshotView.setTranslationX(t * finalPos.x);                    mScreenshotView.setTranslationY(t * finalPos.y);                }            });        }        return anim;    }    private void notifyScreenshotError(Context context) {    }    private void saveScreenshotInWorkerThread(Runnable runnable) {    }}

Check the effect


The following describes the related principles: <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + MaGivdjNvMjnus7P1Mq + Principal + 9q2JpdG1hcM/Principal + principal = "brush: java;"> <frameLayout xmlns: android = "http://schemas.android.com/apk/res/android" android: layout_width = "match_parent" android: layout_height = "match_parent"> </FrameLayout>
There are three layers in the above layout. The bottom background is used for covering, the middle screenshot is used for putting, and the top is also a layer of flash, which is mainly used for reflecting the effect.

The bitmap is placed in the imageview global_screenshot. Corresponding code

mScreenshotView.setImageBitmap(mScreenBitmap);        mScreenshotLayout.requestFocus();        // Setup the animation with the screenshot just taken        if (mScreenshotAnimation != null) {            mScreenshotAnimation.end();            mScreenshotAnimation.removeAllListeners();        }        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);

In this way, we can see on the screen that there is a transitional animation effect, which is

        ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();        ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,                statusBarVisible, navBarVisible);

The two Property animations complete the display-zoom-and-Disappear process. Specifically, the three-layer view above is transformed.

Call in Activity

protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final GlobalScreenshot screenshot = new GlobalScreenshot(this);        findViewById(R.id.main_btn).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                screenshot.takeScreenshot(getWindow().getDecorView(), new Runnable() {                    @Override                    public void run() {                    }                }, true, true);            }        });    }

The following two boolean parameters indicate whether there is a status bar and are used to display different fade-out animations. If one of them is false, it will fade out directly without moving up to the status bar.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.