From 59845d242f52708e5ae3cd8123b5bb5b81683665 Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Wed, 3 May 2023 21:41:30 +0000 Subject: [PATCH] Cancellable gesture should always have cancellation token With the current CancellableHandwritingGesture, cancellationToken is only attached at the time of writeToParcel. However if editor is in same process as IME (i.e. IME contains the editor), writeToParcel will never be called and token will never be set. This change refactors code to not unbeam if we didn't beam cancellation Token. Bug: 280268494 Test: atest InputConnectionEndToEndTest InsertModeGestureTest Change-Id: Idb9292fa087d98395d778dd3cd4a528554909ffc --- .../android/os/CancellationSignalBeamer.java | 14 ++++++++++---- .../CancellableHandwritingGesture.java | 17 ++++++++++++++--- .../view/inputmethod/InsertModeGestureTest.java | 12 ++++++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/core/java/android/os/CancellationSignalBeamer.java b/core/java/android/os/CancellationSignalBeamer.java index b4247831ddc5c..5c0b22172674f 100644 --- a/core/java/android/os/CancellationSignalBeamer.java +++ b/core/java/android/os/CancellationSignalBeamer.java @@ -18,6 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.system.SystemCleaner; import android.util.Pair; import android.view.inputmethod.CancellableHandwritingGesture; @@ -137,7 +138,7 @@ public class CancellationSignalBeamer { * MUST be forwarded to {@link Receiver#cancel} with proper ordering. See * {@link CancellationSignalBeamer} for details. */ - public abstract void onCancel(IBinder token); + public abstract void onCancel(@NonNull IBinder token); /** * A {@link #beam}ed {@link CancellationSignal} was GC'd. @@ -145,7 +146,7 @@ public class CancellationSignalBeamer { * MUST be forwarded to {@link Receiver#forget} with proper ordering. See * {@link CancellationSignalBeamer} for details. */ - public abstract void onForget(IBinder token); + public abstract void onForget(@NonNull IBinder token); private static final ThreadLocal>> sScope = new ThreadLocal<>(); @@ -159,7 +160,8 @@ public class CancellationSignalBeamer { * try-with-resources. {@code null} if {@code cs} was {@code null} or if * {@link HandwritingGesture} isn't {@link CancellableHandwritingGesture cancellable}. */ - public MustClose beamScopeIfNeeded(HandwritingGesture gesture) { + @NonNull + public MustClose beamScopeIfNeeded(@NonNull HandwritingGesture gesture) { if (!(gesture instanceof CancellableHandwritingGesture)) { return null; } @@ -189,7 +191,8 @@ public class CancellationSignalBeamer { * @param cs {@link CancellationSignal} for which token should be returned. * @return {@link IBinder} token. */ - public static IBinder beamFromScope(CancellationSignal cs) { + @NonNull + public static IBinder beamFromScope(@NonNull CancellationSignal cs) { var state = sScope.get(); if (state != null) { var token = state.first.beam(cs); @@ -291,6 +294,7 @@ public class CancellationSignalBeamer { * @return a {@link CancellationSignal} linked to the given token. */ @Nullable + @SuppressLint("VisiblySynchronized") public CancellationSignal unbeam(@Nullable IBinder token) { if (token == null) { return null; @@ -327,6 +331,7 @@ public class CancellationSignalBeamer { * * @param token the token to forget. No-op if {@code null}. */ + @SuppressLint("VisiblySynchronized") public void forget(@Nullable IBinder token) { synchronized (this) { if (mTokenMap.remove(token) != null) { @@ -347,6 +352,7 @@ public class CancellationSignalBeamer { * * @param token the token to forget. No-op if {@code null}. */ + @SuppressLint("VisiblySynchronized") public void cancel(@Nullable IBinder token) { CancellationSignal cs; synchronized (this) { diff --git a/core/java/android/view/inputmethod/CancellableHandwritingGesture.java b/core/java/android/view/inputmethod/CancellableHandwritingGesture.java index 3e7974b0a6b8c..09c2b90068177 100644 --- a/core/java/android/view/inputmethod/CancellableHandwritingGesture.java +++ b/core/java/android/view/inputmethod/CancellableHandwritingGesture.java @@ -17,6 +17,7 @@ package android.view.inputmethod; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.TestApi; import android.os.CancellationSignal; import android.os.CancellationSignalBeamer; @@ -28,10 +29,13 @@ import android.os.IBinder; */ @TestApi public abstract class CancellableHandwritingGesture extends HandwritingGesture { + @NonNull CancellationSignal mCancellationSignal; + @Nullable IBinder mCancellationSignalToken; + /** * Set {@link CancellationSignal} for testing only. * @hide @@ -41,13 +45,20 @@ public abstract class CancellableHandwritingGesture extends HandwritingGesture { mCancellationSignal = cancellationSignal; } + @NonNull CancellationSignal getCancellationSignal() { return mCancellationSignal; } - void unbeamCancellationSignal(CancellationSignalBeamer.Receiver receiver) { - mCancellationSignal = receiver.unbeam(mCancellationSignalToken); - mCancellationSignalToken = null; + /** + * Unbeam cancellation token. + * @hide + */ + public void unbeamCancellationSignal(@NonNull CancellationSignalBeamer.Receiver receiver) { + if (mCancellationSignalToken != null) { + mCancellationSignal = receiver.unbeam(mCancellationSignalToken); + mCancellationSignalToken = null; + } } } diff --git a/core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java b/core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java index 11ddba110f7a1..a94f8772fcd08 100644 --- a/core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java +++ b/core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import android.graphics.PointF; import android.os.CancellationSignal; +import android.os.CancellationSignalBeamer; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -54,4 +55,15 @@ public class InsertModeGestureTest { assertEquals(FALLBACK_TEXT, gesture.getFallbackText()); assertEquals(CANCELLATION_SIGNAL, gesture.getCancellationSignal()); } + + @Test + public void testCancellationSignal() { + var cs = CANCELLATION_SIGNAL; + var gesture = new InsertModeGesture.Builder().setInsertionPoint(INSERTION_POINT) + .setCancellationSignal(CANCELLATION_SIGNAL) + .setFallbackText(FALLBACK_TEXT).build(); + gesture.unbeamCancellationSignal( + new CancellationSignalBeamer.Receiver(true /* cancelOnSenderDeath */)); + assertEquals(gesture.getCancellationSignal(), cs); + } }