[TeX] Add histogram metric for full screen magnification interval of triple tap gesture
Using 25 uniform bins between 0 and 250. A histogram can only be used to record one type of data. Separate the two intervals into two distinct histograms, as this will provide a clearer understanding of how to define the intervals for the adaptive triple tap.
Bug: 364466679
Test: build
Test: manual
Test: atest FullScreenMagnificationGestureHandlerTest
Flag: EXEMPT log only update
Change-Id: I09803b483e47b4a23301f854d628731036659da4
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index aa57e0b..a19fddd 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -68,11 +68,15 @@
import com.android.internal.R;
import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.expresslog.Histogram;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.Flags;
import com.android.server.accessibility.gestures.GestureUtils;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* This class handles full screen magnification in response to touch events.
*
@@ -871,6 +875,15 @@
*/
class DetectingState implements State, Handler.Callback {
+ private static final Histogram HISTOGRAM_FIRST_INTERVAL =
+ new Histogram(
+ "accessibility.value_full_triple_tap_first_interval",
+ new Histogram.UniformOptions(25, 0, 250));
+ private static final Histogram HISTOGRAM_SECOND_INTERVAL =
+ new Histogram(
+ "accessibility.value_full_triple_tap_second_interval",
+ new Histogram.UniformOptions(25, 0, 250));
+
private static final int MESSAGE_ON_TRIPLE_TAP_AND_HOLD = 1;
private static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2;
private static final int MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE = 3;
@@ -1115,6 +1128,12 @@
if (multitapTriggered && numTaps > 2) {
final boolean enabled = !isActivated();
mMagnificationLogger.logMagnificationTripleTap(enabled);
+
+ List<Long> intervals = intervalsOf(mDelayedEventQueue, ACTION_UP);
+ if (intervals.size() >= 2) {
+ HISTOGRAM_FIRST_INTERVAL.logSample(intervals.get(0));
+ HISTOGRAM_SECOND_INTERVAL.logSample(intervals.get(1));
+ }
}
return multitapTriggered;
}
@@ -1144,6 +1163,10 @@
return event != null ? event.getEventTime() : Long.MIN_VALUE;
}
+ public List<Long> intervalsOf(MotionEventInfo info, int eventType) {
+ return MotionEventInfo.intervalsOf(info, eventType);
+ }
+
public int tapCount() {
return MotionEventInfo.countOf(mDelayedEventQueue, ACTION_UP);
}
@@ -1649,7 +1672,7 @@
return !(Float.isNaN(pointerDownLocation.x) && Float.isNaN(pointerDownLocation.y));
}
- private static final class MotionEventInfo {
+ public static final class MotionEventInfo {
private static final int MAX_POOL_SIZE = 10;
private static final Object sLock = new Object();
@@ -1709,6 +1732,14 @@
}
}
+ public MotionEventInfo getNext() {
+ return mNext;
+ }
+
+ public void setNext(MotionEventInfo info) {
+ mNext = info;
+ }
+
private void clear() {
event = recycleAndNullify(event);
rawEvent = recycleAndNullify(rawEvent);
@@ -1721,6 +1752,23 @@
+ countOf(info.mNext, eventType);
}
+ static List<Long> intervalsOf(MotionEventInfo info, int eventType) {
+ List<Long> intervals = new ArrayList<>();
+ MotionEventInfo current = info;
+ MotionEventInfo previous = null;
+
+ while (current != null) {
+ if (current.event.getAction() == eventType) {
+ if (previous != null) {
+ intervals.add(current.event.getDownTime() - previous.event.getDownTime());
+ }
+ previous = current;
+ }
+ current = current.mNext;
+ }
+ return intervals;
+ }
+
public static String toString(MotionEventInfo info) {
return info == null
? ""
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 598d3a3..b745e6a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -32,6 +32,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -64,6 +65,7 @@
import android.graphics.Region;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -105,6 +107,7 @@
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.function.IntConsumer;
@@ -700,6 +703,15 @@
}
@Test
+ public void testIntervalsOf_sendMotionEventInfo_returnMatchIntervals() {
+ FullScreenMagnificationGestureHandler.MotionEventInfo upEventQueue =
+ createEventQueue(ACTION_UP, 0, 100, 300);
+
+ List<Long> upIntervals = mMgh.mDetectingState.intervalsOf(upEventQueue, ACTION_UP);
+ assertEquals(Arrays.asList(100L, 200L), upIntervals);
+ }
+
+ @Test
public void testMagnifierDeactivates_shortcutTriggeredState_returnToIdleState() {
goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED);
@@ -2294,6 +2306,31 @@
return event;
}
+ private FullScreenMagnificationGestureHandler.MotionEventInfo createEventQueue(
+ int eventType, long... delays) {
+ FullScreenMagnificationGestureHandler.MotionEventInfo eventQueue = null;
+ long currentTime = SystemClock.uptimeMillis();
+
+ for (int i = 0; i < delays.length; i++) {
+ MotionEvent event = MotionEvent.obtain(currentTime + delays[i],
+ currentTime + delays[i], eventType, 0, 0, 0);
+
+ FullScreenMagnificationGestureHandler.MotionEventInfo info =
+ FullScreenMagnificationGestureHandler.MotionEventInfo
+ .obtain(event, MotionEvent.obtain(event), 0);
+
+ if (eventQueue == null) {
+ eventQueue = info;
+ } else {
+ FullScreenMagnificationGestureHandler.MotionEventInfo tail = eventQueue;
+ while (tail.getNext() != null) {
+ tail = tail.getNext();
+ }
+ tail.setNext(info);
+ }
+ }
+ return eventQueue;
+ }
private String stateDump() {
return "\nCurrent state dump:\n" + mMgh + "\n" + mHandler.getPendingMessages();