Android16 自定义全局手势 任意界面依次点击屏幕四个角返回Home界面

需求任意app中依次点击屏幕四个角返回Launcher。

主要目标是要捕获全局Touch事件,思路是可以在View.java中dispatchTouchEvent或者参考系统手势实现。鉴于在View中操作容易误触进入其他界面,最后参考系统手势实现。

framework中有一个专门用来监听系统手势的监听器SystemGesturesPointerEventListener.java

直接在这里实现,主要业务在onPointerEvent方法中实现。

先写检测手势触摸的逻辑

java 复制代码
    private void checkFourCornersClick(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        if (screenWidth == 0 || screenHeight == 0) {
            return;
        }
	    //四角位置定位,这部分可以根据自己的需要定义,触摸点的位置,顺序,大小等
        int corner = getCornerPosition(x, y);

        if (corner != -1) {
            if (DEBUG) Slog.d(TAG_CORNERS, "Corner clicked: " + corner + " at (" + x + ", " + y + ")");
			//四角touch顺序判断
            if (isExpectedNextCorner(corner)) {
                mClickedCorners.add(corner);//手势符合后添加到集合
                Slog.i(TAG_CORNERS, "Correct corner order, progress: " + mClickedCorners.size() + "/4");

                resetCornerTimeout();//这里需要判断触摸超时业务
				//四角全部touch后执行下一步任务
                if (mClickedCorners.size() == 4) {
                    Slog.i(TAG_CORNERS, "All four corners clicked! Triggering action.");
                    performFourCornersAction();
                }
            } else {
                Slog.w(TAG_CORNERS, "Wrong corner order. Expected: " + CORRECT_ORDER[mClickedCorners.size()]
                        + ", got: " + corner + ". Reset.");
                resetCornerClick();//未按流程触摸,重置手势集合
            }
        }
    }

四角定位和顺序判断,mCornerSize随意,这里直接写的50

java 复制代码
    private int getCornerPosition(float x, float y) {
        if (x <= mCornerSize && y <= mCornerSize) {
            return 1;//返回值方便顺序判断
        }
        if (x <= mCornerSize && y >= screenHeight - mCornerSize) {
            return 2;
        }
        if (x >= screenWidth - mCornerSize && y <= mCornerSize) {
            return 3;
        }
        if (x >= screenWidth - mCornerSize && y >= screenHeight - mCornerSize) {
            return 4;
        }
        return -1;
    }

	private boolean isExpectedNextCorner(int corner) {
        if (mClickedCorners.size() >= CORRECT_ORDER.length) {
            return false;
        }
        int nextExpected = CORRECT_ORDER[mClickedCorners.size()];
        return corner == nextExpected;
    }

执行手势完成后的任务

java 复制代码
    private void performFourCornersAction() {
        resetCornerClick();

        try {
            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.addCategory(Intent.CATEGORY_HOME);
            mContext.startActivity(intent);
        } catch (Exception e) {
            Slog.e(TAG_CORNERS, "Failed to start activity", e);
        }

        Slog.i(TAG_CORNERS, "Four corners gesture action completed");
    }

onPointerEvent检测手势

java 复制代码
    @Override
    public void onPointerEvent(MotionEvent event) {
        if (mGestureDetector != null && event.isTouchEvent()) {
            mGestureDetector.onTouchEvent(event);
        }
        //mh@预留手势开关{
        if (mEnableFourCornersGestures && event.getAction() == MotionEvent.ACTION_DOWN) {
            checkFourCornersClick(event);
        }
        //mh@}
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                mSwipeFireable = true;
                mDebugFireable = true;
                mDownPointers = 0;
                captureDown(event, 0);
                if (mMouseHoveringAtLeft) {
                    mMouseHoveringAtLeft = false;
       ...

写一个init方法,主要初始化开关和触摸点的大小

java 复制代码
    private void initFourCornersGesture() {
        //触摸超时handler
        mCornerTimeoutRunnable = new Runnable() {
            @Override
            public void run() {
                resetCornerClick();
                if (DEBUG) Slog.d(TAG_CORNERS, "Four corners gesture timeout, reset");
            }
        };
		//自定义ContentObserver,监听开关变化
        mSettingsObserver = new SettingsObserver(mHandler);
        mSettingsObserver.observe();
        updateFourCornersEnabled();
        
        updateCornerSize();

        Slog.i(TAG_CORNERS, "Four corners gesture initialized, enabled: " + mEnableFourCornersGestures
                + ", corner size: " + mCornerSize + "px");
    }

    private void updateFourCornersEnabled() {
        try {
            mEnableFourCornersGestures = Settings.Global.getInt(mContext.getContentResolver(),
                    SETTINGS_KEY_FOUR_CORNERS, 0) == 1;
        } catch (Exception e) {
            Slog.e(TAG_CORNERS, "Failed to read settings, using default", e);
            mEnableFourCornersGestures = true;
        }
    }
	//触摸超时,重置计时器
    private void resetCornerTimeout() {
        mHandler.removeCallbacks(mCornerTimeoutRunnable);
        mHandler.postDelayed(mCornerTimeoutRunnable, CORNER_CLICK_TIMEOUT_MS);
    }
	//重置手势集合
    private void resetCornerClick() {
        mClickedCorners.clear();
        mHandler.removeCallbacks(mCornerTimeoutRunnable);
        if (DEBUG) Slog.d(TAG_CORNERS, "Corner click state reset");
    }

	private class SettingsObserver extends ContentObserver {
        SettingsObserver(Handler handler) {
            super(handler);
        }

        void observe() {
            Uri uri = Settings.Global.getUriFor(SETTINGS_KEY_FOUR_CORNERS);
            mContext.getContentResolver().registerContentObserver(uri, false, this);
            if (DEBUG) Slog.d(TAG_CORNERS, "Settings observer registered for: " + uri);
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            super.onChange(selfChange, uri);
            if (uri == null || SETTINGS_KEY_FOUR_CORNERS.equals(uri.getLastPathSegment())) {
                updateFourCornersEnabled();
                Slog.i(TAG_CORNERS, "Four corners gesture setting changed to: " + mEnableFourCornersGestures);
                
                if (!mEnableFourCornersGestures) {
                    resetCornerClick();
                }
            }
        }
    }

在构造方法中初始化

java 复制代码
	SystemGesturesPointerEventListener(Context context, Handler handler, Callbacks callbacks) {
        mContext = checkNull("context", context);
        mHandler = handler;
        mCallbacks = checkNull("callbacks", callbacks);
        onConfigurationChanged();
        
        initFourCornersGesture();//mh@
    }

最后在设置--开发者选项中实现一个开关控制

参考:

Android R PointerEventDispatcher 触摸事件监听帮助类

Android获取整个屏幕的Touch事件

相关推荐
三少爷的鞋3 小时前
Android 面试系列:Kotlin 协程的 delay 到底发生在哪个线程?
android
TechNomad14 小时前
Kotlin_Lambda编程详解
android·kotlin
熊猫_豆豆15 小时前
QT6 Android C++ 自制美观闹钟
android·c++·qt·闹钟
美狐美颜SDK开放平台15 小时前
Android/iOS直播APP平台开发中的视频美颜SDK优化技巧
android·ios·音视频·美颜sdk·第三方美颜sdk
聚美智数18 小时前
黄历查询-运势查询-国际法定节假日查询-API接口介绍
android·java·数据库
私人珍藏库19 小时前
[Android] 一木百宝箱-万能百宝箱+抖音去水印等几百种功能
android·人工智能·app·软件·多功能
wupa20 小时前
在 enableEdgeToEdge 模式下处理软键盘与自定义面板协同
android
plainGeekDev21 小时前
ProGuard → R8
android·java·kotlin
雨白1 天前
C 语言字符串:从字符数组、指针到核心操作实战
android