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

@Override
public 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() {@Overridepublic 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里的TakeScreenshotServiceComponentName cn = new ComponentName("com.android.systemui","com.android.systemui.screenshot.TakeScreenshotService");Intent intent = new Intent();intent.setComponent(cn);ServiceConnection conn = new ServiceConnection() {@Overridepublic 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() {@Overridepublic 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) {}}}@Overridepublic void onServiceDisconnected(ComponentName name) {}};//绑定Serviceif (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。

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

Android 基于4.4系统截屏的三指截屏相关推荐

  1. 滚动截屏软件_华为指关节截屏不如三指截屏好用?一步到位,实践出真知

    华为手机的指关节截屏功能想必只要是用过的朋友都知道,熟悉的朋友更会以此为依赖,比如我,现在换了个其他品牌手机用,一到截屏的时候还是会不由自主地拿指关节划区截屏,因为指关节截屏不仅仅是双击截屏,这个划区 ...

  2. Android8.1 MTK平台 增加三指截屏(仿IOS左下角显示缩略图点击放大显示)

    效果图 修改后动画如下 系统原动画如下 三指截屏 PhoneWindowManager 同级目录下的 SystemGesturesPointerEventListener.java 主要负责处理界面的 ...

  3. Android N版本 三指截屏

    首先自己恭喜自己找到新的工作,这段时间也把自己的写过的一些功能做个总结. 手势快捷操作现在很多手机厂商都有做,三指截屏只是一个例子,可以通过这个例子去实现某个操作<->某个动作.本文只是写 ...

  4. Android三指截屏的实现

    三指截屏是用户三个手机点击屏幕向下滑,最终调用systemui的截屏服务实现截屏.所以其他只是做一个策略的实现.目前很多不少手机都实现了该功能,因此自己也尝试着实现该功能.1.首先是注册事件,监听用户 ...

  5. Android三指截屏实现,一个简单的三指截屏功能实现

    最近做了很多客制化的Touch需求,很多情况都可以直接通过GestureDetector来完成,这里挑选三指截屏简述原理.先来说说主要思路,在view的onInterceptTouchEvent方法中 ...

  6. SystemUI 三指截屏或Power键加音量键连续截屏比较慢

    不积跬步无以至千里 了解SystemUI模块的童鞋都知道截屏是处在SystemUI的代码逻辑中的,因此这里出现了截屏比较慢的问题,就是你连续的三指截屏或者power+音量键,但是不会去快速的截屏. 修 ...

  7. unity打包的apk无法三指截屏

    unity打包的apk无法三指截屏 环境 华为手机 问题 unity打包的游戏在手机上无法用三指截屏 原因 首先华为手机有一个应用助手 游戏空间的概念或者说是应用. 华为手机当判断此应用为游戏时,会将 ...

  8. Mr.Alright---基于安卓O(8.0)三指截屏的实现

    介绍:使用这种方式下拉状态栏也可以截图,思路就是拦截触摸事件,判断是不是三指并且符合一定的距离,最后发送截屏的广播,代码如下,后面的代码没有修改 //alps/vendor/mediatek/prop ...

  9. Android基于mAppWidget实现手绘地图(三)--环境搭建

    首先,你在Eclispe开发环境中新建一个项目:然后,可以通过Eclispe项目管理工具把这个项目集成到你的app项目中.下面手册会手把手教你如何正确创建一个地图对象. 第一: 新建一个新的Anroi ...

最新文章

  1. MIME 类型(HttpContext.Response.ContentType)列表
  2. 我是IT小小鸟 读书笔记
  3. swoole 定时器
  4. 【cisco下针对冗余链路故障备份的处理措施】
  5. visual studio c/c++变量内存地址里的cc是什么意思?
  6. 她说:我希望你好好写代码
  7. c语言mergesort 参数,归并排序C语言兑现MergeSort
  8. JDK源码系列(6)-StringBuilder
  9. Ubuntu 10.04 Beta 1发布
  10. ubuntu16.04 内核源码编译
  11. Mysql常见的日期查询语句
  12. 导出windows密码技巧总结
  13. java 502错误_Spring Boot连接超时导致502错误的实战案例
  14. steam linux 安装目录,「Linux」- 安装 Steam 客户端 @20210219
  15. 关于URL中带空格的问题
  16. 模电学习笔记(七)——差分放大器电路(减法器)
  17. 如何防止工具(八门神器)进行内存修改(转)
  18. 无线自组网AODV路由机制matlab仿真
  19. 数学分析第二型曲线积分2021.6.2
  20. 行为分析(十):姿态估计部分(六):人体关键点(keypoints)生成算法综述

热门文章

  1. 华为nova7se能云闪付吗_华为Nova支持NFC功能吗 华为Nova能刷公交卡吗【详解】
  2. 千峰JAVA逆战班Day37
  3. 天龙八部选择服务器时显示测速中,这些设置技巧 可以让你的游戏体验大大提升...
  4. 端侧 AI SDK 框架,快手爆款特效落地背后的秘密
  5. 教资学习:法律法规之义务教育法
  6. 计算机临时桌面是怎么回事,win7电脑重启之后卡死在正在准备桌面界面怎么解决...
  7. 通过手动添加id从云音乐接口一键下载音乐(Python3实现)
  8. WIN10 windows+v 打不开剪切板解决方法
  9. 美女主播患癌去世 为生宝宝放弃化疗
  10. Mac电脑mds_store进程占用cpu过高