Android 基于4.4系统截屏的三指截屏_第1张图片
根据上一篇文章Android 4.4系统原生截图解析 ,我们知道系统截屏是调用了TakeScreenshotService,为实现在任何界面都能实现三指截屏,我们就得在PhoneWindow(frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java)中,对其进行触摸监听。即在dispatchTouchEvent中,监听触摸事件。监听完后,触发截屏,大致的思路就是这样了,来看下我们在代码中的具体实现。首先,我们来实现三指触摸事件响应。

@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {    //add by steven zhang    //监听三指滑动事件    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;//Y轴滑动的最大值 private boolean is3Pointer = false;//是否是三指滑动private float downY[] = new float[MAX_POINTER];//手指按下时Y轴坐标private float upY[] = new float[MAX_POINTER];//手指松开时Y轴坐标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();    //获取Settings中是否允许三指截屏,1为允许,非1为不允许    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;    }}

上面我们在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;        }        //初始化要绑定的服务,从这里可以看出要绑定的服务是SystemUI里的TakeScreenshotService        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) {}        };        //绑定Service        if (mContext.bindService(                intent, conn, Context.BIND_AUTO_CREATE)) {            mScreenshotConnection = conn;            //设置超时机制,若超时就解除绑定            postDelayed(mScreenshotTimeout, 10000);        }    }}

从上面的代码可以看出,我只是把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。

".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系统 怎么实现三指截屏

更多相关文章

  1. Android中获取系统通讯录联系人并解决Android6.0权限问题
  2. Android实现获取系统应用列表
  3. Android系统源码给第三方应用开启默认权限
  4. 如何在Android系统源码中添加一个C项目?
  5. Android系统之System Server大纲
  6. Android系统默认Home应用程序(Launcher)的启动过程源代码分析(3)
  7. android获得系统GPU参数 gl.glGetString

随机推荐

  1. Android(安卓)中ShapeDrawable的使用
  2. 图文详解Android属性动画
  3. android读取sim卡联系人
  4. Android 解析jwt遇到java.lang.IllegalAr
  5. 在做Android中GIF遇到不能显示的问题
  6. 谈实现Android定时执行
  7. Android高手应该精通哪些内容?
  8. Android列表分页功能的实现,往下拉时刷新
  9. Android学习之sqlit
  10. Android优酷播放器SDK——Eclipse工程迁