Logs the activated session duration for magnification. (1/2)

Uses the atom MagnificationTripleTapAndHoldActivatedSessionReported in
westworld to log the activated session duration for the window magnifier
which is triggered by the triple-tap-and-hold gesture.

The duration is from the window magnifier's enabled time to its disabled
time.

Bug: 216733714
Test: atest WindowMagnificationGestureHandlerTest
      m statsd_testdrive & statsd_testdrive 452
Change-Id: I423ac39c167c89b0b2db931a616cdd34d6eb151c
Merged-In: I423ac39c167c89b0b2db931a616cdd34d6eb151c
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index a611d65d..3c90239 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -168,6 +168,18 @@
     }
 
     /**
+     * Logs the duration for the magnification session which is activated by the triple tap and
+     * hold gesture.
+     *
+     * @param duration The duration of a triple-tap-and-hold activation session.
+     */
+    public static void logMagnificationTripleTapAndHoldSession(long duration) {
+        FrameworkStatsLog.write(
+                FrameworkStatsLog.MAGNIFICATION_TRIPLE_TAP_AND_HOLD_ACTIVATED_SESSION_REPORTED,
+                duration);
+    }
+
+    /**
      * Logs the warning status of the non-a11yTool service. Calls this when the warning status is
      * changed.
      *
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
index 23cded7..35a1508 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
@@ -193,6 +193,6 @@
     @Override
     public String toString() {
         return "MagnificationGesturesObserver{"
-                + ", mDelayedEventQueue=" + mDelayedEventQueue + '}';
+                + "mDelayedEventQueue=" + mDelayedEventQueue + '}';
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 9ff51ee..cf30a5a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -28,12 +28,14 @@
 import android.annotation.UiContext;
 import android.content.Context;
 import android.graphics.Point;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.util.MathUtils;
 import android.util.Slog;
 import android.view.Display;
 import android.view.MotionEvent;
 
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.EventStreamTransformation;
@@ -91,6 +93,8 @@
     private final Context mContext;
     private final Point mTempPoint = new Point();
 
+    private long mTripleTapAndHoldStartedTime = 0;
+
     public WindowMagnificationGestureHandler(@UiContext Context context,
             WindowMagnificationManager windowMagnificationMgr,
             AccessibilityTraceManager trace,
@@ -213,15 +217,39 @@
                 WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
     }
 
-    private void onTripleTapAndHold(MotionEvent up) {
+    @VisibleForTesting
+    void onTripleTapAndHold(MotionEvent up) {
         if (DEBUG_DETECTING) {
             Slog.i(mLogTag, "onTripleTapAndHold()");
         }
         enableWindowMagnifier(up.getX(), up.getY(),
                 WindowMagnificationManager.WINDOW_POSITION_AT_TOP_LEFT);
+        mTripleTapAndHoldStartedTime = SystemClock.uptimeMillis();
         transitionTo(mViewportDraggingState);
     }
 
+    @VisibleForTesting
+    void releaseTripleTapAndHold() {
+        mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
+        transitionTo(mDetectingState);
+        if (mTripleTapAndHoldStartedTime != 0) {
+            final long duration = SystemClock.uptimeMillis() - mTripleTapAndHoldStartedTime;
+            logMagnificationTripleTapAndHoldSession(duration);
+            mTripleTapAndHoldStartedTime = 0;
+        }
+    }
+
+    /**
+     * Logs the duration for the magnification session which is activated by the triple tap and
+     * hold gesture.
+     *
+     * @param duration The duration of a triple-tap-and-hold activation session.
+     */
+    @VisibleForTesting
+    void logMagnificationTripleTapAndHoldSession(long duration) {
+        AccessibilityStatsLogUtils.logMagnificationTripleTapAndHoldSession(duration);
+    }
+
     void resetToDetectState() {
         transitionTo(mDetectingState);
     }
@@ -310,7 +338,7 @@
         @Override
         public String toString() {
             return "PanningScalingState{"
-                    + "mPanningScalingHandler =" + mPanningScalingHandler + '}';
+                    + "mPanningScalingHandler=" + mPanningScalingHandler + '}';
         }
     }
 
@@ -370,8 +398,7 @@
 
                 case ACTION_UP:
                 case ACTION_CANCEL: {
-                    mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
-                    transitionTo(mDetectingState);
+                    releaseTripleTapAndHold();
                 }
                     break;
             }
@@ -447,7 +474,7 @@
         @Override
         public String toString() {
             return "DetectingState{"
-                    + ", mGestureTimeoutObserver =" + mGesturesObserver
+                    + "mGestureTimeoutObserver=" + mGesturesObserver
                     + '}';
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index e9f0bd9..8890070 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -19,8 +19,12 @@
 import static com.android.server.testutils.TestUtils.strictMock;
 
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
+import android.annotation.UiContext;
+import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -76,7 +80,8 @@
 
     private WindowMagnificationManager mWindowMagnificationManager;
     private MockWindowMagnificationConnection mMockConnection;
-    private WindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
+    private SpyWindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
+    private WindowMagnificationGestureHandler mMockWindowMagnificationGestureHandler;
     @Mock
     MagnificationGestureHandler.Callback mMockCallback;
     @Mock
@@ -89,9 +94,11 @@
                 mock(WindowMagnificationManager.Callback.class), mMockTrace,
                 new MagnificationScaleProvider(mContext));
         mMockConnection = new MockWindowMagnificationConnection();
-        mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
+        mWindowMagnificationGestureHandler = new SpyWindowMagnificationGestureHandler(
                 mContext, mWindowMagnificationManager, mMockTrace, mMockCallback,
                 /** detectTripleTap= */true,   /** detectShortcutTrigger= */true, DISPLAY_0);
+        mMockWindowMagnificationGestureHandler =
+                mWindowMagnificationGestureHandler.getMockGestureHandler();
         mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
         mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class));
     }
@@ -154,6 +161,18 @@
         });
     }
 
+    @Test
+    public void testTripleTapAndHold_logSessionDuration() {
+        // perform triple tap on spy gesture handler
+        goFromStateIdleTo(STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD);
+
+        // perform up event on spy gesture handler
+        returnToNormalFrom(STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD);
+
+        verify(mMockWindowMagnificationGestureHandler)
+                .logMagnificationTripleTapAndHoldSession(anyLong());
+    }
+
     private void forEachState(IntConsumer action) {
         for (int state = FIRST_STATE; state <= LAST_STATE; state++) {
             action.accept(state);
@@ -335,4 +354,31 @@
     private String stateDump() {
         return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
     }
+
+    private static class SpyWindowMagnificationGestureHandler
+            extends WindowMagnificationGestureHandler {
+
+        private final WindowMagnificationGestureHandler mMockWindowMagnificationGestureHandler;
+
+        SpyWindowMagnificationGestureHandler(@UiContext Context context,
+                WindowMagnificationManager windowMagnificationMgr,
+                AccessibilityTraceManager trace,
+                Callback callback,
+                boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) {
+            super(context, windowMagnificationMgr, trace, callback, detectTripleTap,
+                    detectShortcutTrigger, displayId);
+            mMockWindowMagnificationGestureHandler = mock(WindowMagnificationGestureHandler.class);
+        }
+
+        WindowMagnificationGestureHandler getMockGestureHandler() {
+            return mMockWindowMagnificationGestureHandler;
+        }
+
+        @Override
+        void logMagnificationTripleTapAndHoldSession(long duration) {
+            super.logMagnificationTripleTapAndHoldSession(duration);
+            mMockWindowMagnificationGestureHandler
+                    .logMagnificationTripleTapAndHoldSession(duration);
+        }
+    }
 }