三指截屏是用户三个手机点击屏幕向下滑,最终调用systemui的截屏服务实现截屏。所以其他只是做一个策略的实现。目前很多不少手机都实现了该功能,因此自己也尝试着实现该功能。
1.首先是注册事件,监听用户是否设置打开了三指截屏功能。
if(Feature.FEATURE_THREE_FINGER_SCREENSHOT){ resolver.registerContentObserver(
Settings.System.getUriFor("pointer_screenshotchord"), false, this, UserHandle.USER_ALL);
}
监听pointer_screenshotchord 这个值得变化
如果发生了改变获取该值得数据并通过Handler发送消息:
f(Feature.FEATURE_THREE_FINGER_SCREENSHOT){
if (mSystemReady) {
int pointerScreenshotChordMode = Settings.System.getIntForUser(resolver,
"pointer_screenshotchord", 0, UserHandle.USER_CURRENT);
if (mPointerScreenshotChordMode != pointerScreenshotChordMode) {
mPointerScreenshotChordMode = pointerScreenshotChordMode;
mHandler.sendEmptyMessage(pointerScreenshotChordMode != 0 ?
MSG_ENABLE_POINTER_SCREEN_SHOT_CHORD : MSG_DISABLE_POINTER_SCREEN_SHOT_CHORD);
}
}
}
如果pointerScreenshotChordMode!=0则发送MSG_ENABLE_POINTER_SCREEN_SHOT_CHORD消息开启截屏否则取消截屏功能。
下面看看消息怎么处理的。
case MSG_ENABLE_POINTER_SCREEN_SHOT_CHORD:
if (Feature.FEATURE_THREE_FINGER_SCREENSHOT ) {
enableFingerScreenshot(); //开启截屏
}
break;
case MSG_DISABLE_POINTER_SCREEN_SHOT_CHORD:
if (Feature.FEATURE_THREE_FINGER_SCREENSHOT) {
disableFingerScreenshot();//取消截屏
}
break;
接着看看enableFingerScreenshot()这个方法
private void enableFingerScreenshot() {
// TODO Auto-generated method stub
Slog.d(TAG, "enablePointerScreenshotChord");
if (mFingerScreenshotView == null) {
mFingerScreenshotView = new FingerScreenshotView(mContext);
Slog.d(TAG, "new PointerScreenshotChordView");
mFingerScreenshotPointerEventListener = new FingerScreenshotPointerEventListener();
mWindowManagerFuncs.registerPointerEventListener(mFingerScreenshotPointerEventListener);
}
}
可以看出主要是注册事件监听
再看看disableFingerScreenshot():
private void disableFingerScreenshot() {
// TODO Auto-generated method stub
if (mFingerScreenshotPointerEventListener != null) {
mWindowManagerFuncs.unregisterPointerEventListener(
mFingerScreenshotPointerEventListener);
mFingerScreenshotPointerEventListener = null;
}
if (mFingerScreenshotView != null) {
/* WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); wm.removeView(mFingerScreenshotView); */
mFingerScreenshotView = null;
}
}
主要是取消注册事件。
接着就是对事件的监听和响应处理。
private final class FingerScreenshotPointerEventListener implements PointerEventListener {
@Override
public void onPointerEvent(MotionEvent motionEvent) {
if (mFingerScreenshotView != null) {
mFingerScreenshotView.onTouchEvent(motionEvent);
}
}
}
可以看出最后是调用mFingerScreenshotView.onTouchEvent(motionEvent);方法处理
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
int cnt = event.getPointerCount();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
printLog("\n\nACTION_DOWN ");
initThreshold(mContext);
printLog("MIN_DISTANCE :" + MIN_DISTANCE);
fingercount = 0;
ry_pointer3_down = 0;
ry_pointer3_move = 0;
break;
case MotionEvent.ACTION_UP:
if (isShotSuccess() && !isScreenLock(mContext)) {
mHandler.post(mPointerScreenshotRunnable); //三指成功
}
restoreShotScreenPropertiesFlag();
endTime = startTime;
break;
case MotionEvent.ACTION_MOVE:
ry_pointer3_move = (int) event.getY();
if (fingercount < event.getPointerCount()) {
fingercount = event.getPointerCount();
}
if(3 == cnt){
for(int i = 0; i < cnt; i ++){
mEnd[i] = (int) event.getY(i);
}
}
break;
如果三个手指成功了则执行一个线程
mHandler.post(mPointerScreenshotRunnable);
如下:
private final Runnable mPointerScreenshotRunnable = new Runnable() {
public void run() {
Intent intent = new Intent(PointerScreenshotChord); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
};
这个是发送广播消息代表三指成功。
因此在phoneWindow下面必须动态注册广播。
mPointerScreenshotChordReceiver = new PointerScreenshotChordReceiver();
IntentFilter screenOffIntentFilter = new IntentFilter();
screenOffIntentFilter.addAction(PointerScreenshotChord);
context.registerReceiver(mPointerScreenshotChordReceiver, screenOffIntentFilter);
//接收广播
private class PointerScreenshotChordReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Slog.d("PointerScreenshotChordView", "mScreenshotRunnable ");
mHandler.post(mScreenshotRunnable);
}
}
如果接受到了广播执行下面这个线程
private class ScreenshotRunnable implements Runnable {
private int mScreenshotType = TAKE_SCREENSHOT_FULLSCREEN;
public void setScreenshotType(int screenshotType) {
mScreenshotType = screenshotType;
}
@Override
public void run() {
takeScreenshot(mScreenshotType);
}
}
最后调用
takeScreenshot(mScreenshotType);方法截屏
//开始截屏
private void takeScreenshot(final int screenshotType) {
Log.d(TAG, "takeScreenshot: " + screenshotType);
synchronized (mScreenshotLock) {
if (mScreenshotConnection != null) {
if (messenger != null) {
Log.d(TAG, "takeScreenshot use old service to take screenshot");
msg.what = screenshotType;
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) {
}
return;
}
Log.d(TAG, "takeScreenshot before multi-functional screenshot, unbind old service");
mContext.unbindService(mScreenshotConnection);
mScreenshotConnection = null;
messenger = null;
msg = null;
//return;
filletScreen(false);
}
final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE,
SYSUI_SCREENSHOT_SERVICE_EXT);
final Intent serviceIntent = new Intent();
serviceIntent.setComponent(serviceComponent);
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != this) {
return;
}
messenger = new Messenger(service);
msg = Message.obtain(null, screenshotType);
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);
messenger = null;
msg = null;
filletScreen(true);
}
}
}
};
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) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != null) {
mContext.unbindService(mScreenshotConnection);
mScreenshotConnection = null;
mHandler.removeCallbacks(mScreenshotTimeout);
notifyScreenshotError();
messenger = null;
msg = null;
filletScreen(true);
}
}
}
};
if (mContext.bindServiceAsUser(serviceIntent, conn,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
UserHandle.CURRENT)) {
mScreenshotConnection = conn;
//mHandler.postDelayed(mScreenshotTimeout, 10000);
}
}
}
代码有点长,可以去分析,最终调用systemui的服务区开启截屏,看了一下源码,最后服务调用surfaceflinger开启截屏。后面的没再去分析了 。