From adb483a720a8941a12f7b5a56155605ca9da89ea Mon Sep 17 00:00:00 2001 From: Daniel Hsieh Date: Sat, 9 Apr 2022 16:34:45 +0000 Subject: [PATCH] Logs the activated session duration for magnification. (2/2) Uses the atom MagnificationFollowTypingFocusActivatedSessionReported in westworld to log the activated session duration for the window magnifier which its following typing focus is enabled. The duration is accumulated by the time when the window magnifier and the ime are all on. If one of them is off, we would pause the accumulated timer. If a user moves the window magnifier to disables this function, we would stop the accumulated timer and log the duration. Bug: 216733714 Test: m statsd_testdrive & statsd_testdrive 453 atest WindowMagnificationManagerTest Change-Id: I994fc2a3ada8a90fde8b3a0b4f1cc8d7ec21638a --- .../util/AccessibilityStatsLogUtils.java | 11 +++ .../WindowMagnificationManager.java | 83 ++++++++++++++++++- .../WindowMagnificationManagerTest.java | 13 +++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java index a611d65d62605..5ef555e7efe95 100644 --- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java +++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java @@ -167,6 +167,17 @@ public final class AccessibilityStatsLogUtils { convertToLoggingMagnificationMode(mode)); } + /** + * Logs the duration for the window magnifier's following typing focus session. + * + * @param duration The duration of a triple-tap-and-hold activation session. + */ + public static void logMagnificationFollowTypingFocusSession(long duration) { + FrameworkStatsLog.write( + FrameworkStatsLog.MAGNIFICATION_FOLLOW_TYPING_FOCUS_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/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java index ca116e35eb562..09c6ca3a47340 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java @@ -45,6 +45,7 @@ import android.view.accessibility.IWindowMagnificationConnection; import android.view.accessibility.IWindowMagnificationConnectionCallback; import android.view.accessibility.MagnificationAnimationCallback; +import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; @@ -54,6 +55,7 @@ import com.android.server.wm.WindowManagerInternal; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; /** * A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper} @@ -136,6 +138,7 @@ public class WindowMagnificationManager implements private SparseArray mWindowMagnifiers = new SparseArray<>(); // Whether the following typing focus feature for magnification is enabled. private boolean mMagnificationFollowTypingEnabled = true; + @GuardedBy("mLock") private final SparseBooleanArray mIsImeVisibleArray = new SparseBooleanArray(); private boolean mReceiverRegistered = false; @@ -465,18 +468,43 @@ public class WindowMagnificationManager implements } } + private void pauseTrackingTypingFocusRecord(int displayId) { + WindowMagnifier magnifier; + synchronized (mLock) { + magnifier = mWindowMagnifiers.get(displayId); + if (magnifier == null) { + return; + } + } + magnifier.pauseTrackingTypingFocusRecord(); + } + /** * Called when the IME window visibility changed. * * @param shown {@code true} means the IME window shows on the screen. Otherwise, it's hidden. */ void onImeWindowVisibilityChanged(int displayId, boolean shown) { - mIsImeVisibleArray.put(displayId, shown); + synchronized (mLock) { + mIsImeVisibleArray.put(displayId, shown); + } if (shown) { enableAllTrackingTypingFocus(); + } else { + pauseTrackingTypingFocusRecord(displayId); } } + boolean isImeVisible(int displayId) { + synchronized (mLock) { + return mIsImeVisibleArray.get(displayId); + } + } + + void logTrackingTypingFocus(long duration) { + AccessibilityStatsLogUtils.logMagnificationFollowTypingFocusSession(duration); + } + @Override public boolean processScroll(int displayId, float distanceX, float distanceY) { moveWindowMagnification(displayId, -distanceX, -distanceY); @@ -969,6 +997,12 @@ public class WindowMagnificationManager implements private boolean mTrackingTypingFocusEnabled = true; + private volatile long mTrackingTypingFocusStartTime = 0; + private static final AtomicLongFieldUpdater SUM_TIME_UPDATER = + AtomicLongFieldUpdater.newUpdater(WindowMagnifier.class, + "mTrackingTypingFocusSumTime"); + private volatile long mTrackingTypingFocusSumTime = 0; + WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) { mDisplayId = displayId; mWindowMagnificationManager = windowMagnificationManager; @@ -1017,6 +1051,7 @@ public class WindowMagnificationManager implements mEnabled = false; mIdOfLastServiceToControl = INVALID_SERVICE_ID; mTrackingTypingFocusEnabled = false; + pauseTrackingTypingFocusRecord(); return true; } return false; @@ -1069,6 +1104,14 @@ public class WindowMagnificationManager implements } void setTrackingTypingFocusEnabled(boolean trackingTypingFocusEnabled) { + if (mWindowMagnificationManager.isWindowMagnifierEnabled(mDisplayId) + && mWindowMagnificationManager.isImeVisible(mDisplayId) + && trackingTypingFocusEnabled) { + startTrackingTypingFocusRecord(); + } + if (mTrackingTypingFocusEnabled && !trackingTypingFocusEnabled) { + stopAndLogTrackingTypingFocusRecordIfNeeded(); + } mTrackingTypingFocusEnabled = trackingTypingFocusEnabled; } @@ -1076,6 +1119,44 @@ public class WindowMagnificationManager implements return mTrackingTypingFocusEnabled; } + void startTrackingTypingFocusRecord() { + if (mTrackingTypingFocusStartTime == 0) { + mTrackingTypingFocusStartTime = SystemClock.uptimeMillis(); + if (DBG) { + Slog.d(TAG, "start: mTrackingTypingFocusStartTime = " + + mTrackingTypingFocusStartTime); + } + } + } + + void pauseTrackingTypingFocusRecord() { + if (mTrackingTypingFocusStartTime != 0) { + final long elapsed = (SystemClock.uptimeMillis() - mTrackingTypingFocusStartTime); + // update mTrackingTypingFocusSumTime value in an atomic operation + SUM_TIME_UPDATER.addAndGet(this, elapsed); + mTrackingTypingFocusStartTime = 0; + if (DBG) { + Slog.d(TAG, "pause: mTrackingTypingFocusSumTime = " + + mTrackingTypingFocusSumTime + ", elapsed = " + elapsed); + } + } + } + + void stopAndLogTrackingTypingFocusRecordIfNeeded() { + if (mTrackingTypingFocusStartTime != 0 || mTrackingTypingFocusSumTime != 0) { + final long elapsed = mTrackingTypingFocusStartTime != 0 + ? (SystemClock.uptimeMillis() - mTrackingTypingFocusStartTime) : 0; + final long duration = mTrackingTypingFocusSumTime + elapsed; + if (DBG) { + Slog.d(TAG, "stop and log: session duration = " + duration + + ", elapsed = " + elapsed); + } + mWindowMagnificationManager.logTrackingTypingFocus(duration); + mTrackingTypingFocusStartTime = 0; + mTrackingTypingFocusSumTime = 0; + } + } + boolean isEnabled() { return mEnabled; } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java index 978000aa89d36..25ad2be3772e0 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java @@ -23,10 +23,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -292,6 +294,17 @@ public class WindowMagnificationManagerTest { MagnificationScaleProvider.MAX_SCALE); } + @Test + public void logTrackingTypingFocus_processScroll_logDuration() { + WindowMagnificationManager spyWindowMagnificationManager = spy(mWindowMagnificationManager); + spyWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, 50f, 50f); + spyWindowMagnificationManager.onImeWindowVisibilityChanged(TEST_DISPLAY, /* shown */ true); + + spyWindowMagnificationManager.processScroll(TEST_DISPLAY, 10f, 10f); + + verify(spyWindowMagnificationManager).logTrackingTypingFocus(anyLong()); + } + @Test public void onRectangleOnScreenRequested_trackingDisabledByOnDrag_withoutMovingMagnifier() throws RemoteException {