Make IInputMethodManager to oneway (1/N)

Isolate the Completable class from the CancellationGroup
class because not all Completable objects could be cancelled.
So we don’t need to always hold a final CancellationGroup in
Completable class. If the Completable object could be cancelled,
pass it as parameter when doing await.

Bug: 163453493
Test: Manual test with keyboard
Test: atest CtsInputMethodTestCases
Change-Id: If79810d5acc36b5a8c6a2c7cfcabeb4d0ebed197
This commit is contained in:
Wilson Wu
2020-10-19 16:28:34 +08:00
parent c44ef9e253
commit fd64b28073
4 changed files with 329 additions and 324 deletions

View File

@@ -24,11 +24,10 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* A utility class, which works as both a factory class of completable objects and a cancellation
* signal to cancel all the completable objects created by this object.
* A utility class, which works as both a factory class of a cancellation signal to cancel
* all the completable objects.
*/
public final class CancellationGroup {
private final Object mLock = new Object();
@@ -46,274 +45,8 @@ public final class CancellationGroup {
@GuardedBy("mLock")
private boolean mCanceled = false;
/**
* An inner class to consolidate completable object types supported by
* {@link CancellationGroup}.
*/
public static final class Completable {
/**
* Not intended to be instantiated.
*/
private Completable() {
}
/**
* Base class of all the completable types supported by {@link CancellationGroup}.
*/
protected static class ValueBase {
/**
* {@link CountDownLatch} to be signaled to unblock {@link #await(int, TimeUnit)}.
*/
private final CountDownLatch mLatch = new CountDownLatch(1);
/**
* {@link CancellationGroup} to which this completable object belongs.
*/
@NonNull
private final CancellationGroup mParentGroup;
/**
* Lock {@link Object} to guard complete operations within this class.
*/
protected final Object mValueLock = new Object();
/**
* {@code true} after {@link #onComplete()} gets called.
*/
@GuardedBy("mValueLock")
protected boolean mHasValue = false;
/**
* Base constructor.
*
* @param parentGroup {@link CancellationGroup} to which this completable object
* belongs.
*/
protected ValueBase(@NonNull CancellationGroup parentGroup) {
mParentGroup = parentGroup;
}
/**
* @return {@link true} if {@link #onComplete()} gets called already.
*/
@AnyThread
public boolean hasValue() {
synchronized (mValueLock) {
return mHasValue;
}
}
/**
* Called by subclasses to signale {@link #mLatch}.
*/
@AnyThread
protected void onComplete() {
mLatch.countDown();
}
/**
* Blocks the calling thread until at least one of the following conditions is met.
*
* <p>
* <ol>
* <li>This object becomes ready to return the value.</li>
* <li>{@link CancellationGroup#cancelAll()} gets called.</li>
* <li>The given timeout period has passed.</li>
* </ol>
* </p>
*
* <p>The caller can distinguish the case 1 and case 2 by calling {@link #hasValue()}.
* Note that the return value of {@link #hasValue()} can change from {@code false} to
* {@code true} at any time, even after this methods finishes with returning
* {@code true}.</p>
*
* @param timeout length of the timeout.
* @param timeUnit unit of {@code timeout}.
* @return {@code false} if and only if the given timeout period has passed. Otherwise
* {@code true}.
*/
@AnyThread
public boolean await(int timeout, @NonNull TimeUnit timeUnit) {
if (!mParentGroup.registerLatch(mLatch)) {
// Already canceled when this method gets called.
return false;
}
try {
return mLatch.await(timeout, timeUnit);
} catch (InterruptedException e) {
return true;
} finally {
mParentGroup.unregisterLatch(mLatch);
}
}
}
/**
* Completable object of integer primitive.
*/
public static final class Int extends ValueBase {
@GuardedBy("mValueLock")
private int mValue = 0;
private Int(@NonNull CancellationGroup factory) {
super(factory);
}
/**
* Notify when a value is set to this completable object.
*
* @param value value to be set.
*/
@AnyThread
void onComplete(int value) {
synchronized (mValueLock) {
if (mHasValue) {
throw new UnsupportedOperationException(
"onComplete() cannot be called multiple times");
}
mValue = value;
mHasValue = true;
}
onComplete();
}
/**
* @return value associated with this object.
* @throws UnsupportedOperationException when called while {@link #hasValue()} returns
* {@code false}.
*/
@AnyThread
public int getValue() {
synchronized (mValueLock) {
if (!mHasValue) {
throw new UnsupportedOperationException(
"getValue() is allowed only if hasValue() returns true");
}
return mValue;
}
}
}
/**
* Base class of completable object types.
*
* @param <T> type associated with this completable object.
*/
public static class Values<T> extends ValueBase {
@GuardedBy("mValueLock")
@Nullable
private T mValue = null;
protected Values(@NonNull CancellationGroup factory) {
super(factory);
}
/**
* Notify when a value is set to this completable value object.
*
* @param value value to be set.
*/
@AnyThread
void onComplete(@Nullable T value) {
synchronized (mValueLock) {
if (mHasValue) {
throw new UnsupportedOperationException(
"onComplete() cannot be called multiple times");
}
mValue = value;
mHasValue = true;
}
onComplete();
}
/**
* @return value associated with this object.
* @throws UnsupportedOperationException when called while {@link #hasValue()} returns
* {@code false}.
*/
@AnyThread
@Nullable
public T getValue() {
synchronized (mValueLock) {
if (!mHasValue) {
throw new UnsupportedOperationException(
"getValue() is allowed only if hasValue() returns true");
}
return mValue;
}
}
}
/**
* Completable object of {@link java.lang.CharSequence}.
*/
public static final class CharSequence extends Values<java.lang.CharSequence> {
private CharSequence(@NonNull CancellationGroup factory) {
super(factory);
}
}
/**
* Completable object of {@link android.view.inputmethod.ExtractedText}.
*/
public static final class ExtractedText
extends Values<android.view.inputmethod.ExtractedText> {
private ExtractedText(@NonNull CancellationGroup factory) {
super(factory);
}
}
/**
* Completable object of {@link android.view.inputmethod.SurroundingText}.
*/
public static final class SurroundingText
extends Values<android.view.inputmethod.SurroundingText> {
private SurroundingText(@NonNull CancellationGroup factory) {
super(factory);
}
}
}
/**
* @return an instance of {@link Completable.Int} that is associated with this
* {@link CancellationGroup}.
*/
@AnyThread
public Completable.Int createCompletableInt() {
return new Completable.Int(this);
}
/**
* @return an instance of {@link Completable.CharSequence} that is associated with this
* {@link CancellationGroup}.
*/
@AnyThread
public Completable.CharSequence createCompletableCharSequence() {
return new Completable.CharSequence(this);
}
/**
* @return an instance of {@link Completable.ExtractedText} that is associated with this
* {@link CancellationGroup}.
*/
@AnyThread
public Completable.ExtractedText createCompletableExtractedText() {
return new Completable.ExtractedText(this);
}
/**
* @return an instance of {@link Completable.SurroundingText} that is associated with this
* {@link CancellationGroup}.
*/
@AnyThread
public Completable.SurroundingText createCompletableSurroundingText() {
return new Completable.SurroundingText(this);
}
@AnyThread
private boolean registerLatch(@NonNull CountDownLatch latch) {
boolean registerLatch(@NonNull CountDownLatch latch) {
synchronized (mLock) {
if (mCanceled) {
return false;
@@ -329,7 +62,7 @@ public final class CancellationGroup {
}
@AnyThread
private void unregisterLatch(@NonNull CountDownLatch latch) {
void unregisterLatch(@NonNull CountDownLatch latch) {
synchronized (mLock) {
if (mLatchList != null) {
mLatchList.remove(latch);

View File

@@ -0,0 +1,278 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.inputmethod;
import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.annotations.GuardedBy;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* An class to consolidate completable object types supported by
* {@link CancellationGroup}.
*/
public final class Completable {
/**
* Not intended to be instantiated.
*/
private Completable() {
}
/**
* Base class of all the completable types supported by {@link CancellationGroup}.
*/
protected static class ValueBase {
/**
* {@link CountDownLatch} to be signaled to unblock
* {@link #await(int, TimeUnit, CancellationGroup)}.
*/
private final CountDownLatch mLatch = new CountDownLatch(1);
/**
* Lock {@link Object} to guard complete operations within this class.
*/
protected final Object mValueLock = new Object();
/**
* {@code true} after {@link #onComplete()} gets called.
*/
@GuardedBy("mValueLock")
protected boolean mHasValue = false;
/**
* @return {@link true} if {@link #onComplete()} gets called already.
*/
@AnyThread
public boolean hasValue() {
synchronized (mValueLock) {
return mHasValue;
}
}
/**
* Called by subclasses to signale {@link #mLatch}.
*/
@AnyThread
protected void onComplete() {
mLatch.countDown();
}
/**
* Blocks the calling thread until at least one of the following conditions is met.
*
* <p>
* <ol>
* <li>This object becomes ready to return the value.</li>
* <li>{@link CancellationGroup#cancelAll()} gets called.</li>
* <li>The given timeout period has passed.</li>
* </ol>
* </p>
*
* <p>The caller can distinguish the case 1 and case 2 by calling {@link #hasValue()}.
* Note that the return value of {@link #hasValue()} can change from {@code false} to
* {@code true} at any time, even after this methods finishes with returning
* {@code true}.</p>
*
* @param timeout length of the timeout.
* @param timeUnit unit of {@code timeout}.
* @param cancellationGroup {@link CancellationGroup} to cancel completable objects.
* @return {@code false} if and only if the given timeout period has passed. Otherwise
* {@code true}.
*/
@AnyThread
public boolean await(int timeout, @NonNull TimeUnit timeUnit,
@Nullable CancellationGroup cancellationGroup) {
if (cancellationGroup == null) {
return awaitInner(timeout, timeUnit);
}
if (!cancellationGroup.registerLatch(mLatch)) {
// Already canceled when this method gets called.
return false;
}
try {
return awaitInner(timeout, timeUnit);
} finally {
cancellationGroup.unregisterLatch(mLatch);
}
}
private boolean awaitInner(int timeout, @NonNull TimeUnit timeUnit) {
try {
return mLatch.await(timeout, timeUnit);
} catch (InterruptedException e) {
return true;
}
}
}
/**
* Completable object of integer primitive.
*/
public static final class Int extends ValueBase {
@GuardedBy("mValueLock")
private int mValue = 0;
/**
* Notify when a value is set to this completable object.
*
* @param value value to be set.
*/
@AnyThread
void onComplete(int value) {
synchronized (mValueLock) {
if (mHasValue) {
throw new UnsupportedOperationException(
"onComplete() cannot be called multiple times");
}
mValue = value;
mHasValue = true;
}
onComplete();
}
/**
* @return value associated with this object.
* @throws UnsupportedOperationException when called while {@link #hasValue()} returns
* {@code false}.
*/
@AnyThread
public int getValue() {
synchronized (mValueLock) {
if (!mHasValue) {
throw new UnsupportedOperationException(
"getValue() is allowed only if hasValue() returns true");
}
return mValue;
}
}
}
/**
* Base class of completable object types.
*
* @param <T> type associated with this completable object.
*/
public static class Values<T> extends ValueBase {
@GuardedBy("mValueLock")
@Nullable
private T mValue = null;
/**
* Notify when a value is set to this completable value object.
*
* @param value value to be set.
*/
@AnyThread
void onComplete(@Nullable T value) {
synchronized (mValueLock) {
if (mHasValue) {
throw new UnsupportedOperationException(
"onComplete() cannot be called multiple times");
}
mValue = value;
mHasValue = true;
}
onComplete();
}
/**
* @return value associated with this object.
* @throws UnsupportedOperationException when called while {@link #hasValue()} returns
* {@code false}.
*/
@AnyThread
@Nullable
public T getValue() {
synchronized (mValueLock) {
if (!mHasValue) {
throw new UnsupportedOperationException(
"getValue() is allowed only if hasValue() returns true");
}
return mValue;
}
}
}
/**
* @return an instance of {@link Completable.Int}.
*/
public static Completable.Int createInt() {
return new Completable.Int();
}
/**
* @return an instance of {@link Completable.Boolean}.
*/
public static Completable.Boolean createBoolean() {
return new Completable.Boolean();
}
/**
* @return an instance of {@link Completable.CharSequence}.
*/
public static Completable.CharSequence createCharSequence() {
return new Completable.CharSequence();
}
/**
* @return an instance of {@link Completable.ExtractedText}.
*/
public static Completable.ExtractedText createExtractedText() {
return new Completable.ExtractedText();
}
/**
* @return an instance of {@link Completable.SurroundingText}.
*/
public static Completable.SurroundingText createSurroundingText() {
return new Completable.SurroundingText();
}
/**
* Completable object of {@link java.lang.Boolean}.
*/
public static final class Boolean extends Values<java.lang.Boolean> { }
/**
* Completable object of {@link java.lang.CharSequence}.
*/
public static final class CharSequence extends Values<java.lang.CharSequence> { }
/**
* Completable object of {@link android.view.inputmethod.ExtractedText}.
*/
public static final class ExtractedText
extends Values<android.view.inputmethod.ExtractedText> { }
/**
* Completable object of {@link android.view.inputmethod.SurroundingText}.
*/
public static final class SurroundingText
extends Values<android.view.inputmethod.SurroundingText> { }
/**
* Completable object of {@link com.android.internal.view.InputBindResult}.
*/
public static final class InputBindResult
extends Values<com.android.internal.view.InputBindResult> { }
}

View File

@@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicReference;
/**
* Defines a set of factory methods to create {@link android.os.IBinder}-based callbacks that are
* associated with completable objects defined in {@link CancellationGroup.Completable}.
* associated with completable objects defined in {@link Completable}.
*/
public final class ResultCallbacks {
@@ -50,22 +50,22 @@ public final class ResultCallbacks {
}
/**
* Creates {@link IIntResultCallback.Stub} that is to set
* {@link CancellationGroup.Completable.Int} when receiving the result.
* Creates {@link IIntResultCallback.Stub} that is to set {@link Completable.Int} when receiving
* the result.
*
* @param value {@link CancellationGroup.Completable.Int} to be set when receiving the result.
* @param value {@link Completable.Int} to be set when receiving the result.
* @return {@link IIntResultCallback.Stub} that can be passed as a binder IPC parameter.
*/
@AnyThread
public static IIntResultCallback.Stub of(@NonNull CancellationGroup.Completable.Int value) {
final AtomicReference<WeakReference<CancellationGroup.Completable.Int>>
public static IIntResultCallback.Stub of(@NonNull Completable.Int value) {
final AtomicReference<WeakReference<Completable.Int>>
atomicRef = new AtomicReference<>(new WeakReference<>(value));
return new IIntResultCallback.Stub() {
@BinderThread
@Override
public void onResult(int result) {
final CancellationGroup.Completable.Int value = unwrap(atomicRef);
final Completable.Int value = unwrap(atomicRef);
if (value == null) {
return;
}
@@ -76,24 +76,23 @@ public final class ResultCallbacks {
/**
* Creates {@link ICharSequenceResultCallback.Stub} that is to set
* {@link CancellationGroup.Completable.CharSequence} when receiving the result.
* {@link Completable.CharSequence} when receiving the result.
*
* @param value {@link CancellationGroup.Completable.CharSequence} to be set when receiving the
* result.
* @param value {@link Completable.CharSequence} to be set when receiving the result.
* @return {@link ICharSequenceResultCallback.Stub} that can be passed as a binder IPC
* parameter.
*/
@AnyThread
public static ICharSequenceResultCallback.Stub of(
@NonNull CancellationGroup.Completable.CharSequence value) {
final AtomicReference<WeakReference<CancellationGroup.Completable.CharSequence>> atomicRef =
@NonNull Completable.CharSequence value) {
final AtomicReference<WeakReference<Completable.CharSequence>> atomicRef =
new AtomicReference<>(new WeakReference<>(value));
return new ICharSequenceResultCallback.Stub() {
@BinderThread
@Override
public void onResult(CharSequence result) {
final CancellationGroup.Completable.CharSequence value = unwrap(atomicRef);
final Completable.CharSequence value = unwrap(atomicRef);
if (value == null) {
return;
}
@@ -104,24 +103,23 @@ public final class ResultCallbacks {
/**
* Creates {@link IExtractedTextResultCallback.Stub} that is to set
* {@link CancellationGroup.Completable.ExtractedText} when receiving the result.
* {@link Completable.ExtractedText} when receiving the result.
*
* @param value {@link CancellationGroup.Completable.ExtractedText} to be set when receiving the
* result.
* @param value {@link Completable.ExtractedText} to be set when receiving the result.
* @return {@link IExtractedTextResultCallback.Stub} that can be passed as a binder IPC
* parameter.
*/
@AnyThread
public static IExtractedTextResultCallback.Stub of(
@NonNull CancellationGroup.Completable.ExtractedText value) {
final AtomicReference<WeakReference<CancellationGroup.Completable.ExtractedText>>
@NonNull Completable.ExtractedText value) {
final AtomicReference<WeakReference<Completable.ExtractedText>>
atomicRef = new AtomicReference<>(new WeakReference<>(value));
return new IExtractedTextResultCallback.Stub() {
@BinderThread
@Override
public void onResult(android.view.inputmethod.ExtractedText result) {
final CancellationGroup.Completable.ExtractedText value = unwrap(atomicRef);
final Completable.ExtractedText value = unwrap(atomicRef);
if (value == null) {
return;
}
@@ -132,24 +130,23 @@ public final class ResultCallbacks {
/**
* Creates {@link ISurroundingTextResultCallback.Stub} that is to set
* {@link CancellationGroup.Completable.SurroundingText} when receiving the result.
* {@link Completable.SurroundingText} when receiving the result.
*
* @param value {@link CancellationGroup.Completable.SurroundingText} to be set when receiving
* the result.
* @param value {@link Completable.SurroundingText} to be set when receiving the result.
* @return {@link ISurroundingTextResultCallback.Stub} that can be passed as a binder IPC
* parameter.
*/
@AnyThread
public static ISurroundingTextResultCallback.Stub of(
@NonNull CancellationGroup.Completable.SurroundingText value) {
final AtomicReference<WeakReference<CancellationGroup.Completable.SurroundingText>>
@NonNull Completable.SurroundingText value) {
final AtomicReference<WeakReference<Completable.SurroundingText>>
atomicRef = new AtomicReference<>(new WeakReference<>(value));
return new ISurroundingTextResultCallback.Stub() {
@BinderThread
@Override
public void onResult(android.view.inputmethod.SurroundingText result) {
final CancellationGroup.Completable.SurroundingText value = unwrap(atomicRef);
final Completable.SurroundingText value = unwrap(atomicRef);
if (value == null) {
return;
}

View File

@@ -36,6 +36,7 @@ import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.SurroundingText;
import com.android.internal.inputmethod.CancellationGroup;
import com.android.internal.inputmethod.Completable;
import com.android.internal.inputmethod.ResultCallbacks;
import java.lang.ref.WeakReference;
@@ -84,9 +85,10 @@ public class InputConnectionWrapper implements InputConnection {
}
@AnyThread
private static int getResultOrZero(@NonNull CancellationGroup.Completable.Int value,
@NonNull String methodName) {
final boolean timedOut = value.await(MAX_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS);
private static int getResultOrZero(@NonNull Completable.Int value, @NonNull String methodName,
@Nullable CancellationGroup cancellationGroup) {
final boolean timedOut =
value.await(MAX_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS, cancellationGroup);
if (value.hasValue()) {
return value.getValue();
}
@@ -96,9 +98,10 @@ public class InputConnectionWrapper implements InputConnection {
@AnyThread
@Nullable
private static <T> T getResultOrNull(@NonNull CancellationGroup.Completable.Values<T> value,
@NonNull String methodName) {
final boolean timedOut = value.await(MAX_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS);
private static <T> T getResultOrNull(@NonNull Completable.Values<T> value,
@NonNull String methodName, @Nullable CancellationGroup cancellationGroup) {
final boolean timedOut =
value.await(MAX_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS, cancellationGroup);
if (value.hasValue()) {
return value.getValue();
}
@@ -112,14 +115,13 @@ public class InputConnectionWrapper implements InputConnection {
return null;
}
final CancellationGroup.Completable.CharSequence value =
mCancellationGroup.createCompletableCharSequence();
final Completable.CharSequence value = Completable.createCharSequence();
try {
mIInputContext.getTextAfterCursor(length, flags, ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
return getResultOrNull(value, "getTextAfterCursor()");
return getResultOrNull(value, "getTextAfterCursor()", mCancellationGroup);
}
@AnyThread
@@ -128,14 +130,13 @@ public class InputConnectionWrapper implements InputConnection {
return null;
}
final CancellationGroup.Completable.CharSequence value =
mCancellationGroup.createCompletableCharSequence();
final Completable.CharSequence value = Completable.createCharSequence();
try {
mIInputContext.getTextBeforeCursor(length, flags, ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
return getResultOrNull(value, "getTextBeforeCursor()");
return getResultOrNull(value, "getTextBeforeCursor()", mCancellationGroup);
}
@AnyThread
@@ -148,14 +149,13 @@ public class InputConnectionWrapper implements InputConnection {
// This method is not implemented.
return null;
}
final CancellationGroup.Completable.CharSequence value =
mCancellationGroup.createCompletableCharSequence();
final Completable.CharSequence value = Completable.createCharSequence();
try {
mIInputContext.getSelectedText(flags, ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
return getResultOrNull(value, "getSelectedText()");
return getResultOrNull(value, "getSelectedText()", mCancellationGroup);
}
/**
@@ -179,15 +179,14 @@ public class InputConnectionWrapper implements InputConnection {
// This method is not implemented.
return null;
}
final CancellationGroup.Completable.SurroundingText value =
mCancellationGroup.createCompletableSurroundingText();
final Completable.SurroundingText value = Completable.createSurroundingText();
try {
mIInputContext.getSurroundingText(beforeLength, afterLength, flags,
ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
return getResultOrNull(value, "getSurroundingText()");
return getResultOrNull(value, "getSurroundingText()", mCancellationGroup);
}
@AnyThread
@@ -196,14 +195,13 @@ public class InputConnectionWrapper implements InputConnection {
return 0;
}
final CancellationGroup.Completable.Int value =
mCancellationGroup.createCompletableInt();
final Completable.Int value = Completable.createInt();
try {
mIInputContext.getCursorCapsMode(reqModes, ResultCallbacks.of(value));
} catch (RemoteException e) {
return 0;
}
return getResultOrZero(value, "getCursorCapsMode()");
return getResultOrZero(value, "getCursorCapsMode()", mCancellationGroup);
}
@AnyThread
@@ -212,14 +210,13 @@ public class InputConnectionWrapper implements InputConnection {
return null;
}
final CancellationGroup.Completable.ExtractedText value =
mCancellationGroup.createCompletableExtractedText();
final Completable.ExtractedText value = Completable.createExtractedText();
try {
mIInputContext.getExtractedText(request, flags, ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
return getResultOrNull(value, "getExtractedText()");
return getResultOrNull(value, "getExtractedText()", mCancellationGroup);
}
@AnyThread
@@ -423,14 +420,14 @@ public class InputConnectionWrapper implements InputConnection {
// This method is not implemented.
return false;
}
final CancellationGroup.Completable.Int value = mCancellationGroup.createCompletableInt();
final Completable.Int value = Completable.createInt();
try {
mIInputContext.requestUpdateCursorAnchorInfo(cursorUpdateMode,
ResultCallbacks.of(value));
} catch (RemoteException e) {
return false;
}
return getResultOrZero(value, "requestUpdateCursorAnchorInfo()") != 0;
return getResultOrZero(value, "requestUpdateCursorAnchorInfo()", mCancellationGroup) != 0;
}
@AnyThread
@@ -464,13 +461,13 @@ public class InputConnectionWrapper implements InputConnection {
inputMethodService.exposeContent(inputContentInfo, this);
}
final CancellationGroup.Completable.Int value = mCancellationGroup.createCompletableInt();
final Completable.Int value = Completable.createInt();
try {
mIInputContext.commitContent(inputContentInfo, flags, opts, ResultCallbacks.of(value));
} catch (RemoteException e) {
return false;
}
return getResultOrZero(value, "commitContent()") != 0;
return getResultOrZero(value, "commitContent()", mCancellationGroup) != 0;
}
@AnyThread