阅读量:0
系统在frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
处理按键事件,不管是物理按键还是
SystemUI的nav_bar上的虚拟按键(使用了KeyEvent类中的,比如:KeyEvent.KEYCODE_VOLUME_UP).
主要注意的有两个函数:
interceptKeyBeforeDispatching 分发之前拦截事件
interceptKeyBeforeQueueing 加入队列之前拦截事件
长按物理音量上键弹出重启Dialog,去除Dialog界面部分选项
@Override public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event, int policyFlags) { final boolean keyguardOn = keyguardOn(); final int keyCode = event.getKeyCode(); final int repeatCount = event.getRepeatCount(); final int metaState = event.getMetaState(); final int flags = event.getFlags(); final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final boolean canceled = event.isCanceled(); final int displayId = event.getDisplayId(); if (true) { Log.d("tag", "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount=" + repeatCount + " keyguardOn=" + keyguardOn + " canceled=" + canceled); } //add text Log.d("tag", "policyFlags:" + policyFlags);//长按和短按会产生不同的policyFlags //短按流程 按下 down=true repeatCount=0 2次 抬起 down=false repeatCount=0 //长按流程 按下 down=true repeatCount++ 不断自增 抬起 down=false repeatCount=0 if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {//1107296256 long //1644167168 short if (policyFlags == 1107296256 || policyFlags == 1644167168) { if (repeatCount == 20) { mHandler.removeMessages(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS); mHandler.sendEmptyMessageDelayed(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS, 2000 * 1); } return -1; } } //add text //infrare simulate mouse boolean isBox = "box".equals(SystemProperties.get("ro.target.product")); if(isBox){ ... } // Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); msg.setAsynchronous(true); mHandler.sendMessageDelayed(msg,ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); -> powerLongPress(); || showGlobalActions(); frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java //dialog所有菜单选项 <string-array translatable="false" name="config_globalActionsList"> <item>emergency</item> <item>lockdown</item> <item>power</item> <item>restart</item> <item>logout</item> <item>screenshot</item> <item>bugreport</item> </string-array> @VisibleForTesting protected void createActionItems() { // Simple toggle style if there's no vibrator, otherwise use a tri-state if (!mHasVibrator) { mSilentModeAction = new SilentModeToggleAction(); } else { mSilentModeAction = new SilentModeTriStateAction(mAudioManager, mHandler); } mAirplaneModeOn = new AirplaneModeAction(); onAirplaneModeChanged(); mItems.clear(); mOverflowItems.clear(); mPowerItems.clear(); String[] defaultActions = {"restart"};//getDefaultActions();//add text ShutDownAction shutdownAction = new ShutDownAction(); RestartAction restartAction = new RestartAction(); ArraySet<String> addedKeys = new ArraySet<String>(); List<Action> tempActions = new ArrayList<>(); CurrentUserProvider currentUser = new CurrentUserProvider(); //add text // make sure emergency affordance action is first, if needed /*if (mEmergencyAffordanceManager.needsEmergencyAffordance()) { addIfShouldShowAction(tempActions, new EmergencyAffordanceAction()); addedKeys.add(GLOBAL_ACTION_KEY_EMERGENCY); }*/ //add text for (int i = 0; i < defaultActions.length; i++) { String actionKey = defaultActions[i]; if (addedKeys.contains(actionKey)) { // If we already have added this, don't add it again. continue; } ... } //点击dialog外,让它消失 protected static ActionsDialog mDialog;//add static private void initializeLayout() { setContentView(com.android.systemui.R.layout.global_actions_grid_v2); fixNavBarClipping(); mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls); mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view); mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public boolean dispatchPopulateAccessibilityEvent( View host, AccessibilityEvent event) { // Populate the title here, just as Activity does event.getText().add(mContext.getString(R.string.global_actions)); return true; } }); //add text ViewGroup black_view = findViewById(com.android.systemui.R.id.global_actions_grid_root); black_view.setClickable(true); black_view.setOnClickListener(v -> { if (mDialog != null) mDialog.dismiss(); //dismissDialog(); }); //add text mGlobalActionsLayout.setRotationListener(this::onRotate); mGlobalActionsLayout.setAdapter(mAdapter); //衍生案例1: 长按电源键直接关机不弹出dialog void showGlobalActionsInternal() { //add text /*if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } final boolean keyguardShowing = isKeyguardShowingAndNotOccluded(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); // since it took two seconds of long press to bring this up, // poke the wake lock so they have some time to see the dialog. mPowerManager.userActivity(SystemClock.uptimeMillis(), false);*/ mPowerManager.shutdown(false,null,false);//add text //add text } //也可以修改属性实现 ./frameworks/base/core/res/res/values/config.xml <!-- Control the behavior when the user long presses the power button. 0 - Nothing 1 - Global actions menu - 长按电源按钮将显示一个包含各种全局操作选项的菜单 2 - Power off (with confirmation) 长按电源按钮将触发设备的关机动作,弹出需要用户确认的dialog 3 - Power off (without confirmation) 长按电源按钮将触发设备的关机动作,不需要用户确认 4 - Go to voice assist 长按电源按钮将启动语音助手 5 - Go to assistant (Settings.Secure.ASSISTANT) 长按电源按钮将启动设备的默认助手应用程序 --> <integer name="config_longPressOnPowerBehavior">1</integer> //衍生案例2: 长按power键按住三秒即可自动关机 <integer name="config_longPressOnPowerBehavior">3</integer> //先去掉dialog @Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { ... case KeyEvent.KEYCODE_POWER: { //add text 长按3s关机,达不到3s取消 if (down) { Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); msg.setAsynchronous(true); mHandler.sendMessageDelayed(msg,3000); } else { mHandler.removeMessages(MSG_POWER_LONG_PRESS); } //add text break; } //注释掉原来的逻辑 /*case KeyEvent.KEYCODE_POWER: { EventLogTags.writeInterceptPower( KeyEvent.actionToString(event.getAction()), mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter); // Any activity on the power button stops the accessibility shortcut cancelPendingAccessibilityShortcutAction(); result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately if (down) { interceptPowerKeyDown(event, interactive); } else { interceptPowerKeyUp(event, interactive, canceled); } break; }*/ }
Adroid11.0长按power键关机流程分析
Android 设备按键处理
一些按键模拟案例
@Override public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event, int policyFlags) { ... } else if (keyCode == KeyEvent.KEYCODE_MENU) { // Hijack modified menu keys for debugging features final int chordBug = KeyEvent.META_SHIFT_ON; //add text 模拟长按 if (event.getAction() == KeyEvent.ACTION_UP && (event.getEventTime() - event.getDownTime() > 800)) { Log.d(TAG,"this is a KEYCODE_MENU's long press"); //to do return -1; } //add text ... }