diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java index 3c902396d9fe8..6bc7ac6cd7d9b 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 duration for the magnification session which is activated by the triple tap and * hold gesture. 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 {