![这里写图片描述](http://img.blog.csdn.net/20161128141203864)
根据上一篇文章Android 4.4系统原生截图解析 ,我们知道系统截屏是调用了TakeScreenshotService,为实现在任何界面都能实现三指截屏,我们就得在PhoneWindow(frameworks/base/policy/src/com/Android/internal/policy/impl/PhoneWindow.Java)中,对其进行触摸监听。即在dispatchTouchEvent中,监听触摸事件。监听完后,触发截屏,大致的思路就是这样了,来看下我们在代码中的具体实现。首先,我们来实现三指触摸事件响应
@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) { parse3PointerScreenShot(ev); final Callback cb = getCallback(); return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);}private static final int MAX_POINTER = 10;private static final float Y_OFFSET = 180;private boolean is3Pointer = false;private float downY[] = new float[MAX_POINTER];private float upY[] = new float[MAX_POINTER];private float matchY[] = new float[MAX_POINTER];private void clearArrayData(float[] data) { for (int i = 0; i < data.length; i++) { data[i] = 0; }}private void parse3PointerScreenShot(MotionEvent ev) { int actionMasked = ev.getActionMasked(); int pointerCount = ev.getPointerCount(); int value = Settings.System.getInt(mContext.getContentResolver(), "screenshot_pointer", 1); if (value != 1) { return ; } if (pointerCount == 3) { switch (actionMasked) { case MotionEvent.ACTION_POINTER_DOWN: for (int i = 0; i < pointerCount; i++) { int pointerId = ev.getPointerId(i); downY[pointerId] = ev.getY(i); } is3Pointer = true; break; case MotionEvent.ACTION_POINTER_UP: if (is3Pointer) { for (int i = 0; i < pointerCount; i++) { int pointerId = ev.getPointerId(i); upY[pointerId] = ev.getY(i); matchY[pointerId] = Math.abs(upY[pointerId] - downY[pointerId]); } } else { clearArrayData(downY); clearArrayData(upY); clearArrayData(matchY); } break; default: break; } boolean[] flag = new boolean[] { false, false, false, }; for (int i = 0; i < pointerCount; i++) { int pointerId = ev.getPointerId(i); if (matchY[pointerId] > Y_OFFSET) { flag[i] = true; matchY[pointerId] = 0; } } if (flag[0] && flag[1] && flag[2]) { Handler mHandler = new Handler(); mHandler.post(mScreenshotRunnable); } } else { is3Pointer = false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
上面我们在dispatchTouchEvent中接收了触摸事件,如果是我们想要的三指触摸就触摸截屏mHandler.post(mScreenshotRunnable);这里的mScreenshotRunnable就是和Android 4.4系统原生截图解析
里的PhoneWindowManager(frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java)中的mScreenshotRunnable是一样的,我们把它从PhoneWindowManager移植到了PhoneWindow,具体来看代码实现。
private final Runnable mScreenshotRunnable = new Runnable() { @Override public void run() { takeScreenshot(); }};final Object mScreenshotLock = new Object();ServiceConnection mScreenshotConnection = null;final Runnable mScreenshotTimeout = new Runnable() { @Override public void run() { synchronized (mScreenshotLock) { if (mScreenshotConnection != null) { mContext.unbindService(mScreenshotConnection); mScreenshotConnection = null; } } }};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() { @Override public void handleMessage(Message msg) { synchronized (mScreenshotLock) { if (mScreenshotConnection == myConn) { mContext.unbindService(mScreenshotConnection); mScreenshotConnection = null; removeCallbacks(mScreenshotTimeout); } } } }; msg.replyTo = new Messenger(h); msg.arg1 = msg.arg2 = 0; try { messenger.send(msg); } catch (RemoteException e) { } } } @Override public void onServiceDisconnected(ComponentName name) {} }; if (mContext.bindService( intent, conn, Context.BIND_AUTO_CREATE)) { mScreenshotConnection = conn; postDelayed(mScreenshotTimeout, 10000); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
![](http://static.blog.csdn.net/images/save_snippets.png)
private final Runnable mScreenshotRunnable = new Runnable() { @Override public void run() { takeScreenshot(); }};final Object mScreenshotLock = new Object();ServiceConnection mScreenshotConnection = null;final Runnable mScreenshotTimeout = new Runnable() { @Override public void run() { synchronized (mScreenshotLock) { if (mScreenshotConnection != null) { mContext.unbindService(mScreenshotConnection); mScreenshotConnection = null; } } }};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() { @Override public void handleMessage(Message msg) { synchronized (mScreenshotLock) { if (mScreenshotConnection == myConn) { mContext.unbindService(mScreenshotConnection); mScreenshotConnection = null; removeCallbacks(mScreenshotTimeout); } } } }; msg.replyTo = new Messenger(h); msg.arg1 = msg.arg2 = 0; try { messenger.send(msg); } catch (RemoteException e) { } } } @Override public void onServiceDisconnected(ComponentName name) {} }; if (mContext.bindService( intent, conn, Context.BIND_AUTO_CREATE)) { mScreenshotConnection = conn; postDelayed(mScreenshotTimeout, 10000); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
从上面的代码可以看出,我只是把PhoneWindowManager中,截图部分的代码,单独移植到了PhoneWindow中。即可实现,三指截屏了。等等,这样我们真的可以实现截屏了吗?触摸监听、截屏两个都实现了,应该可以实现三指截屏了吧???我们再来看看截屏的实现,它是通过绑定TakeScreenshotService实现的截屏,bindService我们都知道,如果我们的应用跟service不在同一个进程,进行绑定的话会报错,所以,当我们完成上面的步骤后实现三指截屏,系统会报如下的错误。E/AndroidRuntime(3282): java.lang.SecurityException: Not allowed to bind to service Intent { cmp=com.android.systemui/.screenshot.TakeScreenshotService }
E/AndroidRuntime(3282): at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1676)E/AndroidRuntime(3282): at android.app.ContextImpl.bindService(ContextImpl.java:1640)
E/AndroidRuntime(3282): at android.content.ContextWrapper.bindService(ContextWrapper.java:517)E/AndroidRuntime(3282): at com.android.internal.policy.impl.PhoneWindow$DecorView.takeScreenshot(PhoneWindow.java:2205)
E/AndroidRuntime(3282): at com.android.internal.policy.impl.PhoneWindow$DecorView.access$1000(PhoneWindow.java:1950)
E/AndroidRuntime(3282): at com.android.internal.policy.impl.PhoneWindow$DecorView$1.run(PhoneWindow.java:2142)
E/AndroidRuntime(3282): at android.os.Handler.handleCallback(Handler.java:808)
E/AndroidRuntime(3282): at android.os.Handler.dispatchMessage(Handler.java:103)
E/AndroidRuntime(3282): at android.os.Looper.loop(Looper.java:193)
E/AndroidRuntime(3282): at android.app.ActivityThread.main(ActivityThread.java:5292)
E/AndroidRuntime(3282): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(3282): at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime(3282): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
E/AndroidRuntime(3282): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
E/AndroidRuntime(3282): at dalvik.system.NativeStart.main(Native Method)
因此,我们还需要在SystemUI的AndroidManifest.xml中的修改TakeScreenshotService的export为true。
<service android:name=".screenshot.TakeScreenshotService" android:process=":screenshot" android:exported="true" />
这样我们就可以真正的实现三指截屏了。同时,还要注意在PhoneWindow中导入相应的java包。
import android.content.ServiceConnection;import android.content.ComponentName;import android.os.Message;import android.os.Messenger;import android.content.Intent;import android.os.IBinder;import android.os.UserHandle;import android.provider.Settings;
三指截屏的功能,差不多就分析完了。这里给出一个patch文件,感兴趣的同学可以直接看这个文件,就更能明白,我在哪些地方做了系统的修改。
参考文章
android系统 怎么实现三指截屏