(Reprinted please indicate the source: http://blog.csdn.net/buptgshengod) 1. Background
We know that android provides a system screenshot function, that is, to press and hold the power key and the volume reduction button for 0.5 seconds, the system will execute the screenshot function. Therefore, to implement the system screenshot function, capture the functions under the two key combinations of the system, and then drill down one by one. The ScreenShot () function exists under the Surface. java file, which is @ hide. But this is the method of the previous version. It is not applicable after android4.3, because the Surface of/frameworks/base/core/java/android/view. there is no ScreenShot () function in java. I guess google won't be so bad. It will definitely leave an interface for developers at the framework layer, but it will be written elsewhere. As a result, the blogger explored his own ideas and finally found the new ScreenShot function. Here, I will share it with you.
2. Mining Process (1) the key capture in the Android source code is in the file PhoneWindowManager. java (\ frameworks \ base \ policy \ src \ com \ android \ internal \ policy \ impl ).
ase KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_MUTE: { 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(); } } else { mVolumeDownKeyTriggered = false; cancelPendingScreenshotChordAction(); }
We can see that if you press the power button and the volume reduction at the same time, the function will be started,
interceptScreenshotChord();
Let's look at the next function.
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(); mHandler.postDelayed(mScreenshotChordLongPress, ViewConfiguration.getGlobalActionKeyTimeout()); } } }
We can see that this function in handle is the screenshot function we want to execute.
mScreenshotChordLongPress
We enter this function
private final Runnable mScreenshotChordLongPress = new Runnable() { public void run() { takeScreenshot(); } };
We finally found the takeScreenShot, but don't worry. Let's go to this function.
private void takeScreenshot() { synchronized (mScreenshotLock) { if (mScreenshotConnection != null) { return; } ComponentName cn = new ComponentName("com.android.systemui", "com.android.systemui.screenshot.TakeScreenshotService"); 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); } } }
We can see that it starts a service ("com. android. systemui. screenshot. TakeScreenshotService ").
(This also confirms my conjecture that all android functions are implemented by handle through sendmessage and then through service)
(2) Find the service
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); } } }; @Override public IBinder onBind(Intent intent) { return new Messenger(mHandler).getBinder(); }}
We can see that the GlobalScreenshot-like object performs the function.
(3) Enable GlobalScreenshot
/** * 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 = SurfaceControl.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); // Recycle the previous bitmap mScreenBitmap.recycle(); mScreenBitmap = ss; } // Optimizations mScreenBitmap.setHasAlpha(false); mScreenBitmap.prepareToDraw(); // Start the post-screenshot animation startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels, statusBarVisible, navBarVisible); }
Let's take a look at this sentence. We finally found screenshot (), which is changed with the android source code of the lower version. The previous surface operation was written to the surface class, now this surfacecontrol class is added to control the surface.
// Take the screenshot mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
(4) Now we open the surfacecontrol class at/frameworks/base/core/java/android/view.
At the beginning of the code, we can see that this class is hidden by google, so it cannot be called directly. If you want to use the screenshot function, you must compile it in the source code. As for how to call this function, we will talk about it later, have fun!
/** * SurfaceControl * @hide */