8月 252020
转载请注明原文地址:http://bcoder.com/java/implemention-of-back-button-and-home-button-in-android-system-ui-bar
本文基于Android8.1系统编写
一、背景
今天想实现自定义的back和home键,比着葫芦画瓢,把back和home键的部局抄过来了。但怎么也没找到back和home键的java功能实现部分。
后来度娘了一下才找到实现的原理。
参考链接:http://blog.chinaunix.net/uid-701715-id-3054850.html
自己也记录一下
二、按钮的组件类KeyButtonView
在部局中可以看到,back和home键用了一个自定义view,开始我还以为是为了实现按钮的动画效果才自定义了一个这个view,现在发现自己天真了!
KeyButtonView的核心在于,他定义了一个可设置的部局属性keyCode,用于设置按钮对应的键,如下back键的部局代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<com.android.systemui.statusbar.policy.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/back" android:layout_width="@dimen/navigation_key_width" android:layout_height="match_parent" android:layout_weight="0" systemui:keyCode="4" android:scaleType="fitCenter" android:contentDescription="@string/accessibility_back" android:paddingTop="15dp" android:paddingBottom="15dp" android:paddingStart="@dimen/navigation_key_padding" android:paddingEnd="@dimen/navigation_key_padding" |
keyCode=”4″对应的为KeyEvent.KEYCODE_BACK键
在KeyButtonView的构造函数中,读取并保存了这个属性:
1 2 3 4 5 6 7 |
public KeyButtonView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs); //...省略前面的代码 mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0); //...省略后面的代码 } |
如此,在部局文件中设置的keyCode读到了类中
三、模拟发送按键
原理是,拦截onTouch事件,当按钮按下时发送keyCode的ACTION_DOWN操作,当按钮弹开时发送keyCode的ACTION_UP操作,完成一次按键的操作。
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 |
public boolean onTouchEvent(MotionEvent ev) { //...省略部分代码 switch (action) { case MotionEvent.ACTION_DOWN: mDownTime = SystemClock.uptimeMillis(); mLongClicked = false; setPressed(true); if (mCode != 0) { sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime); } else { // Provide the same haptic feedback that the system offers for virtual keys. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); } playSoundEffect(SoundEffectConstants.CLICK); removeCallbacks(mCheckLongPress); postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout()); break; case MotionEvent.ACTION_MOVE: //...省略 case MotionEvent.ACTION_CANCEL: //...省略 break; case MotionEvent.ACTION_UP: final boolean doIt = isPressed() && !mLongClicked; setPressed(false); // Always send a release ourselves because it doesn't seem to be sent elsewhere // and it feels weird to sometimes get a release haptic and other times not. if ((SystemClock.uptimeMillis() - mDownTime) > 150 && !mLongClicked) { performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE); } if (mCode != 0) { if (doIt) { sendEvent(KeyEvent.ACTION_UP, 0); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } else { sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED); } } else { // no key code, just a regular ImageView if (doIt && mOnClickListener != null) { mOnClickListener.onClick(this); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } } removeCallbacks(mCheckLongPress); break; } return true; } |
sendEvent函数,先构造KeyEvent对象,然后通过InputManager发送到系统,代码如下:
1 2 3 4 5 6 7 8 9 10 |
void sendEvent(int action, int flags, long when) { //...省略部分代码 final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0; final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, InputDevice.SOURCE_KEYBOARD); InputManager.getInstance().injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); } |
Sorry, the comment form is closed at this time.