RK:系统手势监听
一.
1.1.需求:从屏幕的左上角为起点,双指触控滑动至屏幕正中央,启动Launcher
1.2.GestureDetector
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | package com.gatsby.mygesturelistener; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; public class MainActivity extends Activity { private MyGestureListener mgListener; private GestureDetector mDetector; private final static String TAG = "gatsby" ; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); mgListener = new MyGestureListener(); mDetector = new GestureDetector( this , mgListener); } @Override public boolean onTouchEvent(MotionEvent event) { return mDetector.onTouchEvent(event); } // 实现GestureListener接口 private class MyGestureListener implements GestureDetector.OnGestureListener { @Override public boolean onDown(MotionEvent motionEvent) { Log.d(TAG, "onDown" ); return false ; } @Override public void onShowPress(MotionEvent motionEvent) { // Log.d(TAG, "onShowPress:手指按下一段时间,不过还没到长按"); Log.d(TAG, "onShowPress" ); } @Override public boolean onSingleTapUp(MotionEvent motionEvent) { // Log.d(TAG, "onSingleTapUp:手指离开屏幕的一瞬间"); Log.d(TAG, "onSingleTapUp" ); return false ; } @Override public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { // Log.d(TAG, "onScroll:在触摸屏上滑动"); Log.d(TAG, "onScroll" ); return false ; } @Override public void onLongPress(MotionEvent motionEvent) { // Log.d(TAG, "onLongPress:长按并且没有松开"); Log.d(TAG, "onLongPress" ); } @Override public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { // Log.d(TAG, "onFling:迅速滑动,并松开"); Log.d(TAG, "onFling" ); Log.d(TAG, "motionEvent->" + motionEvent.getX() + " motionEvent1->" + motionEvent1.getX()); // 从左往右 滑动<50 if (motionEvent.getX() - motionEvent1.getX() < 50 ) { } return false ; } } } |
2.1.MotionEvent、GestureDetector、OnGestureListener
首先,在Android系统中,每一次手势交互都会依照以下顺序执行。
a. 接触接触屏一刹那,触发一个MotionEvent事件。
b. 该事件被OnTouchListener监听,在其onTouch()方法里获得该MotionEvent对象。、
c. 通过GestureDetector(手势识别器)转发次MotionEvent对象至OnGestureListener。·
d. OnGestureListener获得该对象,听根据该对象封装的的信息,做出合适的反馈
MotionEvent: 这个类用于封装手势、触摸笔、轨迹球等等的动作事件。其内部封装了两个重要的属性X和Y,这两个属性分别用于记录横轴和纵轴的坐标。
GestureDetector: 识别各种手势。
OnGestureListener: 这是一个手势交互的监听接口,其中提供了多个抽象方法,并根据GestureDetector的手势识别结果调用相对应的方法。
.系统监听触摸事件
主要就是在SystemGesturesPointerEventListener中加了一个回调方法onMorePointerSwipe,当getPointerCount==2的时候调用,然后在PhoneWindowManager中实现onMorePointerSwipe.
底部、右边滑动,接鼠标时从顶部、底部按住滑动,我们在 Callbacks 中增加一个 void onMorePointerSwipe();
用来回调三指同时滑动的情况,通过 event.getPointerCount() 获取当前屏幕手指按下个数,也可打开调试模式里的指针和触点显示
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java 对导航栏的手势
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // monitor for system gestures mSystemGestures = new SystemGesturesPointerEventListener(context, new SystemGesturesPointerEventListener.Callbacks() { @Override public void onSwipeFromTop() { if (mStatusBar != null ) { requestTransientBars(mStatusBar); } if (SystemProperties.get( "persist.sys.gesshownavibar" , "0" ).equals( "1" )) { if (SystemProperties.get( "persist.sys.hidenavibar" , "0" ).equals( "1" )) { addBar(); } } } @Override public void onSwipeFromBottom() { if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) { requestTransientBars(mNavigationBar); } if (SystemProperties.get( "persist.sys.gesshownavibar" , "0" ).equals( "1" )) { if (SystemProperties.get( "persist.sys.hidenavibar" , "0" ).equals( "1" )) { addBar(); } } } @Override public void onSwipeFromRight() { if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_RIGHT) { requestTransientBars(mNavigationBar); } } @Override public void onSwipeFromLeft() { if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_LEFT) { requestTransientBars(mNavigationBar); } } @Override public void onFling( int duration) { if (mPowerManagerInternal != null ) { mPowerManagerInternal.powerHint( PowerManagerInternal.POWER_HINT_INTERACTION, duration); } } |
二.Android7.1 左上两下 ,右一下 进allapp
2.1.自定义手势
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | --- a/frameworks/base/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java +++ b/frameworks/base/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java @@ - 59 , 6 + 59 , 7 @@ public class SystemGesturesPointerEventListener implements PointerEventListener int screenHeight; int screenWidth; + private int count_point; private int mDownPointers; private boolean mSwipeFireable; private boolean mDebugFireable; @@ - 72 , 7 + 73 , 7 @@ public class SystemGesturesPointerEventListener implements PointerEventListener .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); mSwipeDistanceThreshold = mSwipeStartThreshold; if (DEBUG) Slog.d(TAG, "mSwipeStartThreshold=" + mSwipeStartThreshold - + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold); + + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold); } private static <T> T checkNull(String name, T arg) { @@ - 86 , 6 + 87 , 8 @@ public class SystemGesturesPointerEventListener implements PointerEventListener Handler h = new Handler(Looper.myLooper()); mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), h); mOverscroller = new OverScroller(mContext); + + Slog.d(TAG, "222 screenHeight = " +screenHeight+ " screenWidth = " +screenWidth); } @Override @@ - 102 , 8 + 105 , 26 @@ public class SystemGesturesPointerEventListener implements PointerEventListener if (mMouseHoveringAtEdge) { mMouseHoveringAtEdge = false ; mCallbacks.onMouseLeaveFromEdge(); - } + } mCallbacks.onDown(); + float xhgetX = event.getRawX(); + float xhgetY = event.getRawY(); + Slog.d(TAG, "333 xhgetX = " +xhgetX+ " xhgetY = " +xhgetY); + if (xhgetX <= 100.00 && xhgetY <= 100.00 ){ + if (count_point< 2 ) + count_point ++; + } else if ( (xhgetX <= (screenWidth/ 2 + 50 ) && xhgetX >= (screenWidth/ 2 - 50 ) && xhgetY <= (screenHeight/ 2 + 50 ) && xhgetY >= (screenHeight/ 2 - 50 )) + || (xhgetX >= (screenWidth - 100 ) && xhgetY >= (screenHeight - 100 )) ){ + if (count_point== 2 ) + count_point ++; + } else { + count_point = 0 ; + } + if (count_point == 3 ){ + count_point= 0 ; + mCallbacks.onBootAllApps(); + } + Slog.d(TAG, "333 count_point = " +count_point); break ; case MotionEvent.ACTION_POINTER_DOWN: captureDown(event, event.getActionIndex()); @@ - 282 , 5 + 303 , 6 @@ public class SystemGesturesPointerEventListener implements PointerEventListener void onMouseHoverAtBottom(); void onMouseLeaveFromEdge(); void onDebug(); + void onBootAllApps(); } } |
2.2.注册系统全局广播
使用自定义的广播,然后用命令行测试的时候出现如下warning:
原因:系统对自定义广播做了保护限制 对广播做了保护限定之后只有一定权限的用户才可以使用 否则用一次就会打印一次warning 并且保存异常信息到文件中 所以要在清单文件中注册广播
1 2 3 4 5 6 7 8 9 10 11 | --- a/frameworks/base/core/res/AndroidManifest.xml +++ b/frameworks/base/core/res/AndroidManifest.xml @@ - 509 , 6 + 509 , 8 @@ < protected -broadcast android:name= "android.intent.action.HDMI_PLUG" /> < protected -broadcast android:name= "android.intent.action.USB_CAMERA" /> + < protected -broadcast android:name= "com.xinhua.bootAllApps" /> + <!-- for cec--> < protected -broadcast android:name= "com.rockchip.hdmicec.power_status_changed" /> |
2.3.这里回调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | --- a/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ - 1963 , 6 + 1963 , 14 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void onMouseLeaveFromEdge() { mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); } + + @Override + public void onBootAllApps() { + // + Slog.d( "SystemGestures" , "onBootAllApps" ); + Intent i = new Intent( "com.xinhua.bootAllApps" ); + mContext.sendBroadcastAsUser(i,UserHandle.CURRENT); + } }); mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext); mWindowManagerFuncs.registerPointerEventListener(mSystemGestures); |
2.4.接收广播
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | --- a/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java +++ b/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java @@ - 223 , 6 + 223 , 23 @@ public class Launcher extends Activity } }; + private final BroadcastReceiver allAppReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + if ( "com.xinhua.bootAllApps" .equals(intent.getAction())) { + if (!isAppsViewVisible()) { + getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.TAP, + LauncherLogProto.ALL_APPS_BUTTON); + showAppsView( true /* animated */ , true /* updatePredictedApps */ , + false /* focusSearchBar */ ); + } + } + } + }; + @Thunk Workspace mWorkspace; private View mLauncherView; @Thunk DragLayer mDragLayer; @@ - 456 , 6 + 473 , 10 @@ public class Launcher extends Activity IntentFilter filter = new IntentFilter(ACTION_APPWIDGET_HOST_RESET); registerReceiver(mUiBroadcastReceiver, filter); + + IntentFilter allAppfilter = new IntentFilter(); + allAppfilter.addAction( "com.xinhua.bootAllApps" ); + registerReceiver(allAppReceiver, allAppfilter); mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation); // In case we are on a device with locked rotation, we should look at preferences to check |
三. 系统手势 发出back键值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | diff --git a/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java b/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java index ecfe39b..0a639a2 100755 --- a/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ - 1927 , 6 + 1927 , 15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } @Override + public void onMorePointerSwipe() { + try { + Runtime. getRuntime().exec( "input keyevent 4" ); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override public void onFling( int duration) { if (mPowerManagerInternal != null ) { mPowerManagerInternal.powerHint( diff --git a/frameworks/base/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/frameworks/base/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java index 598c58e..9d131ff 100755 --- a/frameworks/base/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java +++ b/frameworks/base/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java @@ - 44 , 7 + 44 , 9 @@ public class SystemGesturesPointerEventListener implements PointerEventListener private static final int SWIPE_FROM_BOTTOM = 2 ; private static final int SWIPE_FROM_RIGHT = 3 ; private static final int SWIPE_FROM_LEFT = 4 ; - + private static boolean XhDown = false ; + private static boolean Success = false ; + private final Context mContext; private final int mSwipeStartThreshold; private final int mSwipeDistanceThreshold; @@ - 103 , 7 + 105 , 14 @@ public class SystemGesturesPointerEventListener implements PointerEventListener mMouseHoveringAtEdge = false ; mCallbacks.onMouseLeaveFromEdge(); } + mCallbacks.onDown(); mCallbacks.onDown(); + Success = true ; + float xhgetX = event.getRawX(); + float xhgetY = event.getRawY(); + if (xhgetX < 300.00 && xhgetY < 300.00 ){ + XhDown = true ; + } break ; case MotionEvent.ACTION_POINTER_DOWN: captureDown(event, event.getActionIndex()); @@ - 131 , 8 + 140 , 14 @@ public class SystemGesturesPointerEventListener implements PointerEventListener } else if (swipe == SWIPE_FROM_LEFT) { if (DEBUG) Slog.d(TAG, "Firing onSwipeFromLeft" ); mCallbacks.onSwipeFromLeft(); - } - } + } + } + float XhgetX = event.getRawX(); + float XhgetY = event.getRawY(); + if (Success && XhDown && XhgetX > 560.00 && XhgetX < 1360.00 && XhgetY > 400.00 && XhgetY < 740.00 ){ + Success = false ; + mCallbacks.onMorePointerSwipe(); + } break ; case MotionEvent.ACTION_HOVER_MOVE: if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { @@ - 150 , 6 + 165 , 8 @@ public class SystemGesturesPointerEventListener implements PointerEventListener } break ; case MotionEvent.ACTION_UP: + Success = true ; + XhDown = false ; case MotionEvent.ACTION_CANCEL: mSwipeFireable = false ; mDebugFireable = false ; @@ - 282 , 5 + 299 , 6 @@ public class SystemGesturesPointerEventListener implements PointerEventListener void onMouseHoverAtBottom(); void onMouseLeaveFromEdge(); void onDebug(); + void onMorePointerSwipe(); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】