【Android M】平台方实现三指左右滑动任何应用界面截屏
frameworks/base/core/java/com/android/internal/policy/MultiGestureSupport/MultiGestureMonitor.java //新增的类
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
原文地址:http://blog.csdn.net/yelangjueqi/article/details/56275913
源码
1 MultiGestureMonitor.java //多指检测类
package com.example.android;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
/**
* Multi Finger Screenshot Gesture Monitor
*
* @hide
*/
public class MultiGestureMonitor {
private static final String TAG = "FingerScreenShotGesture/" + MultiGestureMonitor.class.getSimpleName();
private final String TAG_EVENT = TAG + "/EventPoint";
private boolean DBG = false;
private boolean isSupportHorizontalSlide = true;
public static final String ACTION_MULTI_FINGER_SCREEN_SHOT = "android.intent.action.MULTI_FINGER_SCREEN_SHOT";
public static final String MULTI_FINGER_SCREEN_SHOT_ENABLED = "multi_finger_screen_shot_enabled";
private final int SUPPORT_FINGER_COUNTS = 3;
private final int HORIZONTAL_SLIDE_OFFSET_DISTANCEY = 300;
private final int HORIZONTAL_SLIDE_OFFSET_DISTANCEX = 160;
private final int VERTICAL_SLIDE_OFFSET_DISTANCEY = 160;
private final int VERTICAL_SLIDE_OFFSET_DISTANCEX = 80;
private final float BASEVELOCOTY = 45;
private int mode;
private float mOldx0;
private float mOldy0;
private float mOldx1;
private float mOldy1;
private float mOldx2;
private float mOldy2;
private float mVelocityX0;
private float mVelocityY0;
private Context mContext;
private VelocityTracker mVelocityTracker;
private boolean mFingerScreenShotEnabled = false;
private boolean getFingerEnable() {
int mFingerMode = Settings.System.getInt(mContext.getContentResolver(), MULTI_FINGER_SCREEN_SHOT_ENABLED, 0);
if (mFingerMode == 1) {
return true;
} else {
return false;
}
}
// private static MultiGestureMonitor sInstance;
//
// public static MultiGestureMonitor getInstance(Context context) {
// if (sInstance == null) {
// sInstance = new MultiGestureMonitor(context);
// }
// return sInstance;
// }
public MultiGestureMonitor(Context context) {
mContext = context;
}
public boolean onTouchEvent(MotionEvent event) {
boolean handled = false;
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
mVelocityTracker.clear();
}
mVelocityTracker.addMovement(event);
mode = 1;
break;
case MotionEvent.ACTION_MOVE:
if (mVelocityTracker != null) {
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
mVelocityX0 = mVelocityTracker.getXVelocity();
mVelocityY0 = mVelocityTracker.getYVelocity();
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode += 1;
if (mode == SUPPORT_FINGER_COUNTS) {
mFingerScreenShotEnabled = getFingerEnable();
try {
mOldx0 = event.getX(event.getPointerId(0));
mOldy0 = event.getY(event.getPointerId(0));
mOldx1 = event.getX(event.getPointerId(1));
mOldy1 = event.getY(event.getPointerId(1));
mOldx2 = event.getX(event.getPointerId(2));
mOldy2 = event.getY(event.getPointerId(2));
if (DBG) {
Log.v(TAG_EVENT, "oldx0:" + mOldx0 + ",oldy0:" + mOldy0 + ",oldx1:" + mOldx1 + ",oldy1:"
+ mOldy1 + ",mOldx2=" + mOldx2 + ",mOldy2=" + mOldy2);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (mode == SUPPORT_FINGER_COUNTS) {
if (!mFingerScreenShotEnabled) {
return false;
}
try {
float newx0 = event.getX(event.getPointerId(0));
float newy0 = event.getY(event.getPointerId(0));
float newx1 = event.getX(event.getPointerId(1));
float newy1 = event.getY(event.getPointerId(1));
float newx2 = event.getX(event.getPointerId(2));
float newy2 = event.getY(event.getPointerId(2));
if (DBG) {
Log.d(TAG_EVENT,
"newx0:" + (Math.abs(newx0 - mOldx0) > HORIZONTAL_SLIDE_OFFSET_DISTANCEX) + ",newy0:"
+ (Math.abs(newy0 - mOldy0) < HORIZONTAL_SLIDE_OFFSET_DISTANCEY) + ",newx1:"
+ (Math.abs(mVelocityX0) > BASEVELOCOTY) + ",newy1:"
+ (Math.abs(newy0 - mOldy0) > VERTICAL_SLIDE_OFFSET_DISTANCEY) + ",newx2="
+ (Math.abs(newx0 - mOldx0) < VERTICAL_SLIDE_OFFSET_DISTANCEX) + ",newy2="
+ (Math.abs(mVelocityY0) > BASEVELOCOTY));
Log.d(TAG_EVENT, "mVelocityX0=" + mVelocityX0 + ",mVelocityY0=" + mVelocityY0);
}
if (isSupportHorizontalSlide) {
if (Math.abs(newx0 - mOldx0) > HORIZONTAL_SLIDE_OFFSET_DISTANCEX
&& Math.abs(newy0 - mOldy0) < HORIZONTAL_SLIDE_OFFSET_DISTANCEY
&& Math.abs(mVelocityX0) > BASEVELOCOTY) {
notifyScreenshotGestureCompleted();
}
} else {
if (Math.abs(newy0 - mOldy0) > VERTICAL_SLIDE_OFFSET_DISTANCEY
&& Math.abs(newx0 - mOldx0) < VERTICAL_SLIDE_OFFSET_DISTANCEX
&& Math.abs(mVelocityY0) > BASEVELOCOTY) {
notifyScreenshotGestureCompleted();
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
mode -= 1;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
Log.v(TAG, "ACTION_UP or ACTION_CANCEL");
mode = 0;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
resetToInitValue();
break;
}
Log.v(TAG, TAG + String.valueOf(handled));
return handled;
}
private void notifyScreenshotGestureCompleted() {
if (mContext != null) {
Intent intent = new Intent();
intent.setAction(ACTION_MULTI_FINGER_SCREEN_SHOT);
mContext.sendBroadcast(intent);
Log.d(TAG, "sendBroadcast:" + ACTION_MULTI_FINGER_SCREEN_SHOT);
}
}
private void resetToInitValue() {
mOldx0 = 0;
mOldy0 = 0;
mOldx1 = 0;
mOldy1 = 0;
mOldx2 = 0;
mOldy2 = 0;
}
}
说明:
该类为多指手势检测的关键类,具体支持几个手指截屏,由常亮"SUPPORT_FINGER_COUNTS"控制,此处为3,即三指截屏
A,MULTI_FINGER_SCREEN_SHOT_ENABLED = "multi_finger_screen_shot_enabled" 为三指截屏的控制开关
B,满足三指滑动手势后调用notifyScreenshotGestureCompleted()方法发送Action到PhoneWindowManager类,调用takeScreenshot()进行截屏
2 PhoneWindow.java
PhoneWindow类修改如下,见高亮部分代码:
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
initFingerScreenshot();
}
......
private final String TAG_FINGER = "/FingerScreenShotGesture";
private boolean DBG = true;
private MultiGestureMonitor mMultiGestureMonitor;
private int mFingerScreenShotEnabled = 0;
private final String MULTI_FINGER_SCREEN_SHOT_ENABLED = MultiGestureMonitor.MULTI_FINGER_SCREEN_SHOT_ENABLED;
private void initFingerScreenshot() {
mMultiGestureMonitor = new MultiGestureMonitor(getContext());
}
private boolean isSupportFingerScreenshot() {
return Settings.System.getInt(getContext().getContentResolver(),
MULTI_FINGER_SCREEN_SHOT_ENABLED, 0) == 1;
}
......
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mMultiGestureMonitor != null) {
boolean ishanded = mMultiGestureMonitor.onTouchEvent(ev);
if (DBG) Log.v(TAG, "dispatchTouchEvent:" + String.valueOf(ishanded));
if (ishanded) {
return true;
}
}
final Callback cb = getCallback();
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
: super.dispatchTouchEvent(ev);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理