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
- Android4.0 源码-Screenshot 截屏流程分析
- Android4.0源码Launcher启动流程分析
- 浅析android锁屏开机绘制流程(基于android4.0源码分析)
- 浅析android锁屏开机绘制流程(基于android4.0源码分析) .
- android4.0屏幕截屏流程
- Android4.0.3源码分析——开机流程之Zygote
- Android4.0蓝牙打开流程分析
- android4 SystemUI 流程分析
- android4.2 锁屏源码分析
- android4.2 锁屏源码分析
- android4.2 锁屏源码分析
- Android4.0 Launcher源码分析系列(四)
- Android4.0 Launcher 源码分析系列
- Android4.0 Launcher 源码分析系列
- Android4.0 Bitmap Parcel传输源码分析
- android4.4 PowerManagerService流程分析
- android4.4 PowerManagerService流程分析
- Framework层Android4.4锁屏流程分析
- 分布式搜索elasticsearch------索引修复
- android USB如何修改可移动磁盘里的属性名?
- 向量相似度距离常用公式
- Windows程序调试----第一部分 调试策略----第3章 使用断言
- 七大排序算法系列之希尔排序
- Android4.0 源码-Screenshot 截屏流程分析
- ubuntu 命令行模式和图形界面切换问题
- 程序打包
- RIP的定期选路更新
- Ubuntu使用技巧
- Vmware What is the location of the directory of C header files that match your running问题的解决
- RGraph: Free HTML5 and JavaScript charts
- xmllint: command not found
- mysql 替换函数replace()实现mysql 替换字符串