Android三指截屏的实现

 三指截屏是用户三个手机点击屏幕向下滑,最终调用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开启截屏。后面的没再去分析了 。

    原文作者:一抹夕阳815
    原文地址: https://blog.csdn.net/linliang815/article/details/76187424
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞