Files
mg4/app/src/main/java/com/evsuite/abrp/DoublePressDetector.java
T
nilsandClaude Opus 5.5 af15b15db1 App 2.7.0: voice-key double press opens the app; no scroll jumps
Steering wheel: a double press of the voice key (code 287) opens the
app. The floating button from 2.6.0 does not show over the MG4
launcher, so this is the way back into the app. The head unit reports
keys as the broadcast com.saic.keyevent.hardkey.report, whose extras
are not documented: the receiver tries the usual names (and an
embedded KeyEvent), and counts one press per report whichever way the
up/down field turns out to work; long presses never open the app. The
last 20 reports are listed raw on the Logs tab, so if the guess
misses, a photo of that list gives the real format. A switch in the
Upload tab turns it off. DoublePressDetector (500 ms window) has 5
tests; on the emulator, simulated double presses open the app and
single presses, other keys and long presses do not.

Scrolling: pages jumped back to the top on every 2 s refresh. A stack
trace on the emulator showed why: ViewPager2's RecyclerView lays the
pages out while measuring, at a provisional height, and
ScrollView.onLayout clamps the position to 0. StableScrollView keeps
the driver's position across layouts and is now the root of every
page; the scrolled Charging page stays put across refreshes.

Vehicle tab: all six value tiles, including both range estimates, sit
in one row at the top, so nothing needs scrolling at 1920x720.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 23:24:48 +02:00

47 lines
1.7 KiB
Java

package com.evsuite.abrp;
/**
* Spots a double press of one steering-wheel key from the head unit's key broadcasts.
*
* The broadcast format is not documented, so this copes with all the shapes it could take:
* - no up/down information at all: every broadcast is one press;
* - separate down and up broadcasts: only releases count. If the meaning of the action field
* is the other way round, downs count instead — still exactly one per press, so a double
* press is found either way;
* - a long press resets, so holding the key never opens anything.
*
* Android-free and unit-tested; the window is longer than the stock 300 ms, because a
* deliberate double press on a steering wheel is slower than one on a touch screen.
*/
final class DoublePressDetector {
static final long WINDOW_MS = 500;
private final int keyCode;
private long lastPressAt = Long.MIN_VALUE;
DoublePressDetector(int keyCode) {
this.keyCode = keyCode;
}
/**
* @param down true for a key-down, false for a release, null when the broadcast does not say
* @param longPress true when the broadcast marks a long press
* @return true exactly once per double press
*/
synchronized boolean accept(int code, Boolean down, boolean longPress, long atMillis) {
if (code != keyCode) return false;
if (longPress) {
lastPressAt = Long.MIN_VALUE;
return false;
}
if (Boolean.TRUE.equals(down)) return false;
if (lastPressAt != Long.MIN_VALUE && atMillis - lastPressAt <= WINDOW_MS) {
lastPressAt = Long.MIN_VALUE; // a third press starts over
return true;
}
lastPressAt = atMillis;
return false;
}
}