Skip to content

Commit 98392ef

Browse files
author
Jeff Brown
committed
Fix bug in KeyButtonView key injection logic.
Bug: 5299191 Bug: 5300282 Only send keys when mCode != 0. Simplified the logic for repeating / non-repeating keys. Key down / up are always correlated with touch down / up, the only thing that's special is that we detect long press for repeating keys and not for others. Ensure that up or cancel is always sent for every key that is generated. Previously it was possible for keys to get stuck down if touch moved out of the button's active area. Removed the funky HOME long press timer. We don't need it since we can rely on the long-press flag instead. Since the system UI is in direct control of key repeating and long-press behavior for the keys it inject, this eliminates the need for special hacks to circumvent the timer. Ensure that the same haptic feedback is provided for all keys, including the recent apps key. Previously this only worked because the code was injecting a bogus key with code 0. Don't generate repeated haptic feedback for virtual keys even when those keys are injected. This doesn't happen for virtual keys synthesized by the InputReader because it never injects repeats itself (the InputDispatcher synthesizes them), but it is an issue for the KeyButtonView. Change-Id: I8b3615dde738af28e76898d161d6ce9a883b59ec
1 parent 6515f50 commit 98392ef

File tree

2 files changed

+47
-76
lines changed

2 files changed

+47
-76
lines changed

packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java

Lines changed: 37 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,17 @@
1616

1717
package com.android.systemui.statusbar.policy;
1818

19-
import android.animation.Animator;
2019
import android.animation.AnimatorSet;
2120
import android.animation.ObjectAnimator;
2221
import android.content.Context;
2322
import android.content.res.TypedArray;
24-
import android.graphics.drawable.AnimationDrawable;
2523
import android.graphics.drawable.Drawable;
2624
import android.graphics.Canvas;
2725
import android.graphics.RectF;
2826
import android.os.RemoteException;
2927
import android.os.SystemClock;
3028
import android.os.ServiceManager;
3129
import android.util.AttributeSet;
32-
import android.util.Slog;
3330
import android.view.accessibility.AccessibilityEvent;
3431
import android.view.HapticFeedbackConstants;
3532
import android.view.IWindowManager;
@@ -40,9 +37,7 @@
4037
import android.view.SoundEffectConstants;
4138
import android.view.View;
4239
import android.view.ViewConfiguration;
43-
import android.view.ViewGroup;
4440
import android.widget.ImageView;
45-
import android.widget.RemoteViews.RemoteView;
4641

4742
import com.android.systemui.R;
4843

@@ -53,9 +48,7 @@ public class KeyButtonView extends ImageView {
5348

5449
IWindowManager mWindowManager;
5550
long mDownTime;
56-
boolean mSending;
5751
int mCode;
58-
int mRepeat;
5952
int mTouchSlop;
6053
Drawable mGlowBG;
6154
float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f;
@@ -67,12 +60,7 @@ public void run() {
6760
if (isPressed()) {
6861
// Slog.d("KeyButtonView", "longpressed: " + this);
6962
if (mCode != 0) {
70-
mRepeat++;
71-
sendEvent(KeyEvent.ACTION_DOWN,
72-
KeyEvent.FLAG_FROM_SYSTEM
73-
| KeyEvent.FLAG_VIRTUAL_HARD_KEY
74-
| KeyEvent.FLAG_LONG_PRESS);
75-
63+
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
7664
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
7765
} else {
7866
// Just an old-fashioned ImageView
@@ -217,64 +205,54 @@ public boolean onTouchEvent(MotionEvent ev) {
217205
case MotionEvent.ACTION_DOWN:
218206
//Slog.d("KeyButtonView", "press");
219207
mDownTime = SystemClock.uptimeMillis();
220-
mRepeat = 0;
221-
mSending = true;
222208
setPressed(true);
223-
sendEvent(KeyEvent.ACTION_DOWN,
224-
KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, mDownTime);
209+
if (mCode != 0) {
210+
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
211+
} else {
212+
// Provide the same haptic feedback that the system offers for virtual keys.
213+
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
214+
}
225215
if (mSupportsLongpress) {
226216
removeCallbacks(mCheckLongPress);
227217
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
228-
} else {
229-
mSending = false;
230-
sendEvent(KeyEvent.ACTION_UP,
231-
KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, mDownTime);
232-
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
233-
playSoundEffect(SoundEffectConstants.CLICK);
234218
}
235219
break;
236220
case MotionEvent.ACTION_MOVE:
237-
if (mSending) {
238-
x = (int)ev.getX();
239-
y = (int)ev.getY();
240-
setPressed(x >= -mTouchSlop
241-
&& x < getWidth() + mTouchSlop
242-
&& y >= -mTouchSlop
243-
&& y < getHeight() + mTouchSlop);
244-
}
221+
x = (int)ev.getX();
222+
y = (int)ev.getY();
223+
setPressed(x >= -mTouchSlop
224+
&& x < getWidth() + mTouchSlop
225+
&& y >= -mTouchSlop
226+
&& y < getHeight() + mTouchSlop);
245227
break;
246228
case MotionEvent.ACTION_CANCEL:
247229
setPressed(false);
248-
if (mSending) {
249-
mSending = false;
250-
sendEvent(KeyEvent.ACTION_UP,
251-
KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY
252-
| KeyEvent.FLAG_CANCELED);
253-
if (mSupportsLongpress) {
254-
removeCallbacks(mCheckLongPress);
255-
}
230+
if (mCode != 0) {
231+
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
232+
}
233+
if (mSupportsLongpress) {
234+
removeCallbacks(mCheckLongPress);
256235
}
257236
break;
258237
case MotionEvent.ACTION_UP:
259238
final boolean doIt = isPressed();
260239
setPressed(false);
261-
if (mSending) {
262-
mSending = false;
263-
final int flags = KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY;
264-
if (mSupportsLongpress) {
265-
removeCallbacks(mCheckLongPress);
266-
}
267-
268-
if (mCode != 0) {
269-
if (doIt) {
270-
sendEvent(KeyEvent.ACTION_UP, flags);
271-
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
272-
playSoundEffect(SoundEffectConstants.CLICK);
273-
}
240+
if (mCode != 0) {
241+
if (doIt) {
242+
sendEvent(KeyEvent.ACTION_UP, 0);
243+
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
244+
playSoundEffect(SoundEffectConstants.CLICK);
274245
} else {
275-
// no key code, just a regular ImageView
276-
if (doIt) performClick();
246+
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
277247
}
248+
} else {
249+
// no key code, just a regular ImageView
250+
if (doIt) {
251+
performClick();
252+
}
253+
}
254+
if (mSupportsLongpress) {
255+
removeCallbacks(mCheckLongPress);
278256
}
279257
break;
280258
}
@@ -287,8 +265,11 @@ void sendEvent(int action, int flags) {
287265
}
288266

289267
void sendEvent(int action, int flags, long when) {
290-
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, mRepeat,
291-
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags, InputDevice.SOURCE_KEYBOARD);
268+
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
269+
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
270+
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
271+
flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
272+
InputDevice.SOURCE_KEYBOARD);
292273
try {
293274
//Slog.d(TAG, "injecting event " + ev);
294275
mWindowManager.injectInputEventNoWait(ev);

policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -629,15 +629,6 @@ boolean isDeviceProvisioned() {
629629
mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
630630
}
631631

632-
/**
633-
* When a home-key longpress expires, close other system windows and launch the recent apps
634-
*/
635-
Runnable mHomeLongPress = new Runnable() {
636-
public void run() {
637-
handleLongPressOnHome();
638-
}
639-
};
640-
641632
private void handleLongPressOnHome() {
642633
// We can't initialize this in init() since the configuration hasn't been loaded yet.
643634
if (mLongPressOnHomeBehavior < 0) {
@@ -1418,11 +1409,6 @@ public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, in
14181409
// it handle it, because that gives us the correct 5 second
14191410
// timeout.
14201411
if (keyCode == KeyEvent.KEYCODE_HOME) {
1421-
// Clear a pending HOME longpress if the user releases Home
1422-
if (!down) {
1423-
mHandler.removeCallbacks(mHomeLongPress);
1424-
}
1425-
14261412
// If we have released the home key, and didn't do anything else
14271413
// while it was pressed, then it is time to go home!
14281414
if (mHomePressed && !down) {
@@ -1470,12 +1456,15 @@ public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, in
14701456
}
14711457
}
14721458
}
1473-
1474-
if (down && repeatCount == 0) {
1475-
if (!keyguardOn) {
1476-
mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
1459+
1460+
if (down) {
1461+
if (repeatCount == 0) {
1462+
mHomePressed = true;
1463+
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
1464+
if (!keyguardOn) {
1465+
handleLongPressOnHome();
1466+
}
14771467
}
1478-
mHomePressed = true;
14791468
}
14801469
return true;
14811470
} else if (keyCode == KeyEvent.KEYCODE_MENU) {
@@ -2518,7 +2507,8 @@ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean i
25182507
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
25192508
}
25202509

2521-
if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
2510+
if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
2511+
&& event.getRepeatCount() == 0) {
25222512
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
25232513
}
25242514

0 commit comments

Comments
 (0)