Power长按、组合键分析

来源:互联网 发布:休格兰特 知乎 编辑:程序博客网 时间:2024/06/14 09:42

1.Power长按功能原理

 当按下power时

[java] view plain copy print?
  1. Log.i(TAG, "PowerKey down, isScreenOn = " + isScreenOn);  
  2. interceptPowerKeyDown(!isScreenOn || hungUp  
  3.         || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);  
[java] view plain copy print?
  1. private void interceptPowerKeyDown(boolean handled) {  
  2.     mPowerKeyHandled = handled;  
  3.     if (!handled || mChangeLongPressPowerKey) {  
  4.         if(mChangeLongPressPowerKey) {  
  5.             Log.d(TAG,"fast boot acquire cpu wakelock for timeout :"+(ViewConfiguration.getGlobalActionKeyTimeout()+100));  
  6.             PowerManager.WakeLock fastBootWake = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "FastBootWake");  
  7.             fastBootWake.acquire(ViewConfiguration.getGlobalActionKeyTimeout()+100);  
  8.          }  
  9.         mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());  
  10.     }  
  11. }  

抬起手时
[java] view plain copy print?
  1. Log.i(TAG, "PowerKey up");  
  2. mPowerKeyTriggered = false;  
  3. cancelPendingScreenshotChordAction();  
  4. if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {  
  5.     result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;  
  6. }  
  7. mPendingPowerKeyUpCanceled = false;  
[java] view plain copy print?
  1. private boolean interceptPowerKeyUp(boolean canceled) {  
  2.     if (!mPowerKeyHandled) {  
  3.         mHandler.removeCallbacks(mPowerLongPress);  
  4.         return !canceled;  
  5.     }  
  6.     if (mChangeLongPressPowerKey) {  
  7.         mHandler.removeCallbacks(mPowerLongPress);  
  8.     }  
  9.     return false;  
  10. }  

根据以上代码分析知,在亮屏、音量键没触发、power键没进行挂电话行为时,按下power会进入mPowerLongPress启动的倒计时,当抬起手时会判断power键的事件是否被消耗,如果没被消耗则移除mPowerLongPress事件,并返回传进来的boolean的相反值。

mPendingPowerKeyUpCanceled的值控制如下

[java] view plain copy print?
  1. private void cancelPendingPowerKeyAction() {  
  2.     if (!mPowerKeyHandled) {  
  3.         mHandler.removeCallbacks(mPowerLongPress);  
  4.     }  
  5.     if (mPowerKeyTriggered) {  
  6.         mPendingPowerKeyUpCanceled = true;  
  7.     }  
  8. }  

总结来说:要想实现长按,需要1.一个boolean值用于判断按下的事件是否消费,如mPowerKeyHandled。2.handler延迟执行长按的事件,并且在长按事件的执行代码中把事件boolean设置为消费状态。3.up事件中判断这次按下事件是否被消耗,如果没则处理单点流程。

长按实现:记录下第一次按下的时间,记录此次事件是否被消费,在down事件中判断是否达到了长按时间,在up事件中把事件归零并判断事件是否消费并重置。

2.组合键原理

长按power+音量下可以截图,以此为例分析

在power键的down事件中有如下代码

[java] view plain copy print?
  1. if (isScreenOn && !mPowerKeyTriggered  
  2.         && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {  
  3.     mPowerKeyTriggered = true;  
  4.     mPowerKeyTime = event.getDownTime();  
  5.     interceptScreenshotChord();  
  6. }  

[java] view plain copy print?
  1. private void interceptScreenshotChord() {  
  2.     if (mScreenshotChordEnabled  
  3.             && mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {  
  4.         final long now = SystemClock.uptimeMillis();  
  5.         if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS  
  6.                 && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {  
  7.             mVolumeDownKeyConsumedByScreenshotChord = true;  
  8.             cancelPendingPowerKeyAction();  
  9.   
  10.             mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());  
  11.         }  
  12.     }  
  13. }  

音量-按键down事件
[java] view plain copy print?
  1. if (isScreenOn && !mVolumeDownKeyTriggered  
  2.         && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {  
  3.     mVolumeDownKeyTriggered = true;  
  4.     mVolumeDownKeyTime = event.getDownTime();  
  5.     mVolumeDownKeyConsumedByScreenshotChord = false;  
  6.     cancelPendingPowerKeyAction();  
  7.     interceptScreenshotChord();  
  8. }  
根据以上代码可以分析出;power键按下时记下按下的时间并且mPowerKeyTriggered设为true,音量键同样如此,两个都调用了interceptScreenshotChord()方法,也就是说先按下哪个键不影响。在interceptScreenshotChord()方法中,如果power被触发、音量down被触发,音量up没被触发则继续判断两个按键按下的间隔是否在一定时间内,如果是则开始进入截屏流程,并把mVolumeDownKeyConsumedByScreenshotChord设为true,mVolumeDownKeyConsumedByScreenshotChord值用于阻止音量按键事件往下传递用,在interceptKeyBeforeDispatching方法内
[java] view plain copy print?
  1. if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) {  
  2.     if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) {  
  3.         final long now = SystemClock.uptimeMillis();  
  4.         final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;  
  5.         if (now < timeoutTime) {  
  6.             return timeoutTime - now;  
  7.         }  
  8.     }  
  9.     if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN  
  10.             && mVolumeDownKeyConsumedByScreenshotChord) {  
  11.         if (!down) {  
  12.             mVolumeDownKeyConsumedByScreenshotChord = false;  
  13.         }  
  14.         return -1;  
  15.     }  
  16. }  
可以看出,如果先按的是音量-键,那么在一定时间内事件是没有被传递下去,当抬手时则mVolumeDownKeyConsumedByScreenshotChord=true.不过mVolumeDownKeyConsumedByScreenshotChord好像没什么用。

总结:要想实现组合键,1、记录两个按键的按下时间。2、记录两个按键是否按下触发。3、每个按键按下时触发同一个方法并在此方法内判读两个按键按下的时间差是否在一定时间内,如果是则组合按键生效。

注意:power按键之所以在组合按键起效时不响应点击或者长按事件,因为处理时判断了音量键是否按下去了,如果按下了则不起效。而如果power键先按,则在音量键按下时调用了mVolumeDownKeyConsumedByScreenshotChord

[java] view plain copy print?
  1. private void cancelPendingPowerKeyAction() {  
  2.     if (!mPowerKeyHandled) {  
  3.         mHandler.removeCallbacks(mPowerLongPress);  
  4.     }  
  5.     if (mPowerKeyTriggered) {  
  6.         mPendingPowerKeyUpCanceled = true;  
  7.     }  
  8. }  
mPendingPowerKeyUpCanceled的用途是阻止power松开时灭屏