Android4.0 源码-Screenshot 截屏流程分析

来源:互联网 发布:上海银行淘宝卡面签 编辑:程序博客网 时间:2024/05/29 12:27


LOG: I/ActivityManager(  195): Start proc com.android.systemui:screenshot for service com.android.systemui/.screenshot.TakeScreenshotServ}

1)  按下组合键,进如PhoneWindowManager.java (/framework/base/policy/src/com/android/internal/policy/impl )

 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;        final boolean canceled = event.isCanceled();        final int keyCode = event.getKeyCode();        ....       switch (keyCode) {           ....                if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {                    if (down) {                        if (isScreenOn && !mVolumeDownKeyTriggered                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {                            mVolumeDownKeyTriggered = true;                            mVolumeDownKeyTime = event.getDownTime();                            mVolumeDownKeyConsumedByScreenshotChord = false;                            cancelPendingPowerKeyAction();                            interceptScreenshotChord();                      Slog.d(TAG,"[Paul]interceptKeyBeforeQueueing.........Call  interceptScreenshotChord().... 1 "); //按组合键之后先到这                         }                    } else {                        mVolumeDownKeyTriggered = false;                        cancelPendingScreenshotChordAction();                     Slog.d(TAG,"[Paul]interceptKeyBeforeQueueing.........Call cancelPendingScreenshotChordAction().... 2 "); //按键放手到这                                }                } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {                       ....  }

2)Call interceptScreenshotChord() 方法;


 private void cancelPendingPowerKeyAction() {        if (!mPowerKeyHandled) {            mHandler.removeCallbacks(mPowerLongPress);        }        if (mPowerKeyTriggered) {            mPendingPowerKeyUpCanceled = true;                      Slog.d(TAG,"[Paul]cancelPendingPowerKeyAction...........5 "); //paul        }    }    private void interceptScreenshotChord() {        if (mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {            final long now = SystemClock.uptimeMillis();            if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS                    && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {                mVolumeDownKeyConsumedByScreenshotChord = true;                cancelPendingPowerKeyAction();                      Slog.d(TAG,"[Paul]interceptScreenshotChord...........6 "); //paul                mHandler.postDelayed(mScreenshotChordLongPress,                        ViewConfiguration.getGlobalActionKeyTimeout());            }        }    }

3)运行takeScreenshot() 方法:

 private final Runnable mScreenshotChordLongPress = new Runnable() {        public void run() {                      Slog.d(TAG,"[Paul]mScreenshotChordLongPress...........7 "); //paul            takeScreenshot();        }    };

4)哈哈  跑到TakeScreenshotService里去了

  private void takeScreenshot() {        synchronized (mScreenshotLock) {            if (mScreenshotConnection != null) {                return;            }            ComponentName cn = new ComponentName("com.android.systemui",                    "com.android.systemui.screenshot.TakeScreenshotService");                      Slog.d(TAG,"[Paul]takeScreenshot()...................8 "); //paul            Intent intent = new Intent();            intent.setComponent(cn);            ServiceConnection conn = new ServiceConnection() {                @Override                public void onServiceConnected(ComponentName name, IBinder service) {                    synchronized (mScreenshotLock) {                        if (mScreenshotConnection != this) {                            return;                        }                        Messenger messenger = new Messenger(service);                        Message msg = Message.obtain(null, 1);                        final ServiceConnection myConn = this;                        Handler h = new Handler(mHandler.getLooper()) {                            @Override                            public void handleMessage(Message msg) {                                synchronized (mScreenshotLock) {                                    if (mScreenshotConnection == myConn) {                                        mContext.unbindService(mScreenshotConnection);                                        mScreenshotConnection = null;                                        mHandler.removeCallbacks(mScreenshotTimeout);                                    }                                }                            }                        };                        msg.replyTo = new Messenger(h);                        msg.arg1 = msg.arg2 = 0;                        if (mStatusBar != null && mStatusBar.isVisibleLw())                            msg.arg1 = 1;                        if (mNavigationBar != null && mNavigationBar.isVisibleLw())                            msg.arg2 = 1;                        try {                            messenger.send(msg);                        } catch (RemoteException e) {                        }                    }                }                @Override                public void onServiceDisconnected(ComponentName name) {}            };            if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {                mScreenshotConnection = conn;                mHandler.postDelayed(mScreenshotTimeout, 10000);            }        }    }

5)TakeScreenshotService.java  (/frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot )

     

public class TakeScreenshotService extends Service {    private static final String TAG = "TakeScreenshotService";    private static GlobalScreenshot mScreenshot;    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case 1:                    final Messenger callback = msg.replyTo;                    if (mScreenshot == null) {                        mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);                    }                    mScreenshot.takeScreenshot(new Runnable() {                        @Override public void run() {                            Message reply = Message.obtain(null, 1);                            try {                                callback.send(reply);                            } catch (RemoteException e) {                            }                        }                    }, msg.arg1 > 0, msg.arg2 > 0);            }        }    };

6) GlobalScreenshot.java (/frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot )  终于找到真相了,隐藏在这里!这个方法会完成截图动作,以及显示动画。


 /**     * Takes a screenshot of the current display and shows an animation.     */    void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {        // We need to orient the screenshot correctly (and the Surface api seems to take screenshots        // only in the natural orientation of the device :!)        mDisplay.getRealMetrics(mDisplayMetrics);        float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};        float degrees = getDegreesForRotation(mDisplay.getRotation());        boolean requiresRotation = (degrees > 0);        if (requiresRotation) {            // Get the dimensions of the device in its native orientation            mDisplayMatrix.reset();            mDisplayMatrix.preRotate(-degrees);            mDisplayMatrix.mapPoints(dims);            dims[0] = Math.abs(dims[0]);            dims[1] = Math.abs(dims[1]);        }        // Take the screenshot        mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);        if (mScreenBitmap == null) {            notifyScreenshotError(mContext, mNotificationManager);            finisher.run();            return;        }        if (requiresRotation) {            // Rotate the screenshot to the current orientation            Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,                    mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);            Canvas c = new Canvas(ss);            c.translate(ss.getWidth() / 2, ss.getHeight() / 2);            c.rotate(degrees);            c.translate(-dims[0] / 2, -dims[1] / 2);            c.drawBitmap(mScreenBitmap, 0, 0, null);            c.setBitmap(null);            mScreenBitmap = ss;        }        // Optimizations        mScreenBitmap.setHasAlpha(false);        mScreenBitmap.prepareToDraw();        // Start the post-screenshot animation        startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,                statusBarVisible, navBarVisible);    }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();        }        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);            }        });        mScreenshotLayout.post(new Runnable() {            @Override            public void run() {                // Play the shutter sound to notify that we've taken a screenshot                mCameraSound.playSound(CameraSound.SHUTTER_CLICK);  //截图会播放快门音啊                mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);                mScreenshotView.buildLayer();                mScreenshotAnimation.start();            }        });

接下来关键看把截图的图片存放在何处?!

7)还是刚刚上面的那个类里。

/**     * Creates a new worker thread and saves the screenshot to the media store.     */    private void saveScreenshotInWorkerThread(Runnable finisher) {        SaveImageInBackgroundData data = new SaveImageInBackgroundData();        data.context = mContext;        data.image = mScreenBitmap;        data.iconSize = mNotificationIconSize;        data.finisher = finisher;        new SaveImageInBackgroundTask(mContext, data, mNotificationManager,                SCREENSHOT_NOTIFICATION_ID).execute(data);    }

8)这回是到类外个类里面,发现在这里有environment里面的成员。

SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data,            NotificationManager nManager, int nId) {        Resources r = context.getResources();        // Prepare all the output metadata        mImageTime = System.currentTimeMillis();        String imageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(mImageTime));        String imageDir = Environment.getExternalStoragePublicDirectory(                Environment.DIRECTORY_PICTURES).getAbsolutePath();        mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);        mImageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, imageDir,                SCREENSHOTS_DIR_NAME, mImageFileName);        // Create the large notification icon        int imageWidth = data.image.getWidth();        int imageHeight = data.image.getHeight();        int iconWidth = data.iconSize;        int iconHeight = data.iconSize;        if (imageWidth > imageHeight) {            iconWidth = (int) (((float) iconHeight / imageHeight) * imageWidth);        } else {            iconHeight = (int) (((float) iconWidth / imageWidth) * imageHeight);        }        Bitmap rawIcon = Bitmap.createScaledBitmap(data.image, iconWidth, iconHeight, true);        Bitmap croppedIcon = Bitmap.createBitmap(rawIcon, (iconWidth - data.iconSize) / 2,                (iconHeight - data.iconSize) / 2, data.iconSize, data.iconSize);        // Show the intermediate notification        mTickerAddSpace = !mTickerAddSpace;        mNotificationId = nId;        mNotificationManager = nManager;        mNotificationBuilder = new Notification.Builder(context)            .setTicker(r.getString(R.string.screenshot_saving_ticker)                    + (mTickerAddSpace ? " " : ""))            .setContentTitle(r.getString(R.string.screenshot_saving_title))            .setContentText(r.getString(R.string.screenshot_saving_text))            .setSmallIcon(R.drawable.stat_notify_image)            .setWhen(System.currentTimeMillis());        Notification n = mNotificationBuilder.getNotification();        n.flags |= Notification.FLAG_NO_CLEAR;        mNotificationManager.notify(nId, n);        // On the tablet, the large icon makes the notification appear as if it is clickable (and        // on small devices, the large icon is not shown) so defer showing the large icon until        // we compose the final post-save notification below.        mNotificationBuilder.setLargeIcon(croppedIcon);    }

9)Environment.java (framework/base/core/java/android/os )


public static File getExternalStoragePublicDirectory(String type) {        return new File(getExternalStorageDirectory(), type);    }

   public static File getExternalStorageDirectory() {        return EXTERNAL_STORAGE_DIRECTORY;    }

 private static final File EXTERNAL_STORAGE_DIRECTORY            = getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard");


终于截图功能基本上分析完成,存放路径也找到,很简单,一路下来~~ENVIRONMENT.JAVA 里面好多资源啊:

参考如下:http://blog.csdn.net/djpraul/article/details/8727534



原创粉丝点击