Use AndroidFuture instead

This CL replaces our inhouse utility classes in favor of an existing
alternative AndroidFuture, which allows us to remove 8 files in total.

Several downsides are:

  * We lose compile-time type checking in the remote end, because AIDL
    does not support generics.
  * AndroidFuture<T> does not support any raw Binder interfaces.  For
    instance, AndroidFuture<IInputContentUriToken> would crash due to
    java.lang.ClassCastException at run time. You must use IBinder
    instead and manually create a stub object in the receiver side.
  * Data transfer would be a bit slower for primitive types and much
    more slower for Parcelable types, because AndroidFuture internally
    uses Parcel.{read,write}Value(), which is known to be around 4x
    slower than Parcel.{read,write}TypedObject() for Parcelable
    objects [1][2].
  * When you find an AndroidFuture<T> on a code, you have to figure
    out whether the code is running on the source side or remote side.
    If you are on the source side, what you see on that object is an
    aggregation of the computations on both the source and remote
    ends, which is probably easy to understand.  If you are on the
    remote side, however, you will never observe any computation
    result in the source side.  What you can observe in the remote
    side remains to be your local data that is specific to your remote
    process.

Other than above, there should be no observable semantic change in
this CL.

  [1]: https://developer.android.com/reference/android/os/Parcel
  [2]: I29548ce6c2e5886f0e90a5dc70d8e9ecc0fb25a8
       b293d933e0

Bug: 192412909
Bug: 195699814
Test: presubmit
Change-Id: I74657826a99b11ca1f86932f8f41cca6e449cc8a
This commit is contained in:
Yohei Yukawa
2021-08-29 13:30:03 -07:00
parent ba8cdf5dcf
commit b2d09de1f9
14 changed files with 210 additions and 754 deletions

View File

@@ -1,140 +0,0 @@
/*
* 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.NonNull;
import android.os.RemoteException;
import java.util.function.BooleanSupplier;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
/**
* Defines a set of helper methods to callback corresponding results in {@link ResultCallbacks}.
*/
public final class CallbackUtils {
/**
* Not intended to be instantiated.
*/
private CallbackUtils() {
}
/**
* A utility method using given {@link IBooleanResultCallback} to callback the result.
*
* @param callback {@link IBooleanResultCallback} to be called back.
* @param resultSupplier the supplier from which the result is provided.
*/
public static void onResult(@NonNull IBooleanResultCallback callback,
@NonNull BooleanSupplier resultSupplier) {
boolean result = false;
Throwable exception = null;
try {
result = resultSupplier.getAsBoolean();
} catch (Throwable throwable) {
exception = throwable;
}
try {
if (exception != null) {
callback.onError(ThrowableHolder.of(exception));
return;
}
callback.onResult(result);
} catch (RemoteException ignored) { }
}
/**
* A utility method using given {@link IIntResultCallback} to callback the result.
*
* @param callback {@link IIntResultCallback} to be called back.
* @param resultSupplier the supplier from which the result is provided.
*/
public static void onResult(@NonNull IIntResultCallback callback,
@NonNull IntSupplier resultSupplier) {
int result = 0;
Throwable exception = null;
try {
result = resultSupplier.getAsInt();
} catch (Throwable throwable) {
exception = throwable;
}
try {
if (exception != null) {
callback.onError(ThrowableHolder.of(exception));
return;
}
callback.onResult(result);
} catch (RemoteException ignored) { }
}
/**
* A utility method using given {@link IVoidResultCallback} to callback the result.
*
* @param callback {@link IVoidResultCallback} to be called back.
* @param runnable to execute the given method
*/
public static void onResult(@NonNull IVoidResultCallback callback,
@NonNull Runnable runnable) {
Throwable exception = null;
try {
runnable.run();
} catch (Throwable throwable) {
exception = throwable;
}
try {
if (exception != null) {
callback.onError(ThrowableHolder.of(exception));
return;
}
callback.onResult();
} catch (RemoteException ignored) { }
}
/**
* A utility method using given {@link IInputContentUriTokenResultCallback} to callback the
* result.
*
* @param callback {@link IInputContentUriTokenResultCallback} to be called back.
* @param resultSupplier the supplier from which the result is provided.
*/
public static void onResult(@NonNull IInputContentUriTokenResultCallback callback,
@NonNull Supplier<IInputContentUriToken> resultSupplier) {
IInputContentUriToken result = null;
Throwable exception = null;
try {
result = resultSupplier.get();
} catch (Throwable throwable) {
exception = throwable;
}
try {
if (exception != null) {
callback.onError(ThrowableHolder.of(exception));
return;
}
callback.onResult(result);
} catch (RemoteException ignored) { }
}
}

View File

@@ -1,24 +0,0 @@
/*
* 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 com.android.internal.inputmethod.ThrowableHolder;
oneway interface IBooleanResultCallback {
void onResult(boolean result);
void onError(in ThrowableHolder exception);
}

View File

@@ -1,21 +0,0 @@
/*
* 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;
oneway interface ICharSequenceResultCallback {
void onResult(in CharSequence result);
}

View File

@@ -1,23 +0,0 @@
/*
* 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.view.inputmethod.ExtractedText;
oneway interface IExtractedTextResultCallback {
void onResult(in ExtractedText result);
}

View File

@@ -1,25 +0,0 @@
/*
* 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 com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.ThrowableHolder;
oneway interface IInputContentUriTokenResultCallback {
void onResult(in IInputContentUriToken result);
void onError(in ThrowableHolder exception);
}

View File

@@ -28,14 +28,14 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.SurroundingText;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.view.IInputContext;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
/**
* A stateless wrapper of {@link com.android.internal.view.IInputContext} to encapsulate boilerplate
* code around {@link CompletableFuture} and {@link RemoteException}.
* code around {@link AndroidFuture} and {@link RemoteException}.
*/
public final class IInputContextInvoker {
@@ -63,19 +63,19 @@ public final class IInputContextInvoker {
*
* @param length {@code length} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
* @return {@link CompletableFuture<CharSequence>} that can be used to retrieve the invocation
* @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
* result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
public CompletableFuture<CharSequence> getTextAfterCursor(int length, int flags) {
final CompletableFuture<CharSequence> value = new CompletableFuture<>();
public AndroidFuture<CharSequence> getTextAfterCursor(int length, int flags) {
final AndroidFuture<CharSequence> future = new AndroidFuture<>();
try {
mIInputContext.getTextAfterCursor(length, flags, ResultCallbacks.ofCharSequence(value));
mIInputContext.getTextAfterCursor(length, flags, future);
} catch (RemoteException e) {
value.completeExceptionally(e);
future.completeExceptionally(e);
}
return value;
return future;
}
/**
@@ -83,39 +83,38 @@ public final class IInputContextInvoker {
*
* @param length {@code length} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
* @return {@link CompletableFuture<CharSequence>} that can be used to retrieve the invocation
* @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
* result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
public CompletableFuture<CharSequence> getTextBeforeCursor(int length, int flags) {
final CompletableFuture<CharSequence> value = new CompletableFuture<>();
public AndroidFuture<CharSequence> getTextBeforeCursor(int length, int flags) {
final AndroidFuture<CharSequence> future = new AndroidFuture<>();
try {
mIInputContext.getTextBeforeCursor(length, flags,
ResultCallbacks.ofCharSequence(value));
mIInputContext.getTextBeforeCursor(length, flags, future);
} catch (RemoteException e) {
value.completeExceptionally(e);
future.completeExceptionally(e);
}
return value;
return future;
}
/**
* Invokes {@link IInputContext#getSelectedText(int, ICharSequenceResultCallback)}.
*
* @param flags {@code flags} parameter to be passed.
* @return {@link CompletableFuture<CharSequence>} that can be used to retrieve the invocation
* @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
* result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
public CompletableFuture<CharSequence> getSelectedText(int flags) {
final CompletableFuture<CharSequence> value = new CompletableFuture<>();
public AndroidFuture<CharSequence> getSelectedText(int flags) {
final AndroidFuture<CharSequence> future = new AndroidFuture<>();
try {
mIInputContext.getSelectedText(flags, ResultCallbacks.ofCharSequence(value));
mIInputContext.getSelectedText(flags, future);
} catch (RemoteException e) {
value.completeExceptionally(e);
future.completeExceptionally(e);
}
return value;
return future;
}
/**
@@ -125,40 +124,39 @@ public final class IInputContextInvoker {
* @param beforeLength {@code beforeLength} parameter to be passed.
* @param afterLength {@code afterLength} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
* @return {@link CompletableFuture<SurroundingText>} that can be used to retrieve the
* @return {@link AndroidFuture<SurroundingText>} that can be used to retrieve the
* invocation result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
public CompletableFuture<SurroundingText> getSurroundingText(int beforeLength, int afterLength,
public AndroidFuture<SurroundingText> getSurroundingText(int beforeLength, int afterLength,
int flags) {
final CompletableFuture<SurroundingText> value = new CompletableFuture<>();
final AndroidFuture<SurroundingText> future = new AndroidFuture<>();
try {
mIInputContext.getSurroundingText(beforeLength, afterLength, flags,
ResultCallbacks.ofSurroundingText(value));
mIInputContext.getSurroundingText(beforeLength, afterLength, flags, future);
} catch (RemoteException e) {
value.completeExceptionally(e);
future.completeExceptionally(e);
}
return value;
return future;
}
/**
* Invokes {@link IInputContext#getCursorCapsMode(int, IIntResultCallback)}.
*
* @param reqModes {@code reqModes} parameter to be passed.
* @return {@link CompletableFuture<Integer>} that can be used to retrieve the invocation
* @return {@link AndroidFuture<Integer>} that can be used to retrieve the invocation
* result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
public CompletableFuture<Integer> getCursorCapsMode(int reqModes) {
final CompletableFuture<Integer> value = new CompletableFuture<>();
public AndroidFuture<Integer> getCursorCapsMode(int reqModes) {
final AndroidFuture<Integer> future = new AndroidFuture<>();
try {
mIInputContext.getCursorCapsMode(reqModes, ResultCallbacks.ofInteger(value));
mIInputContext.getCursorCapsMode(reqModes, future);
} catch (RemoteException e) {
value.completeExceptionally(e);
future.completeExceptionally(e);
}
return value;
return future;
}
/**
@@ -167,20 +165,20 @@ public final class IInputContextInvoker {
*
* @param request {@code request} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
* @return {@link CompletableFuture<ExtractedText>} that can be used to retrieve the invocation
* @return {@link AndroidFuture<ExtractedText>} that can be used to retrieve the invocation
* result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
public CompletableFuture<ExtractedText> getExtractedText(ExtractedTextRequest request,
public AndroidFuture<ExtractedText> getExtractedText(ExtractedTextRequest request,
int flags) {
final CompletableFuture<ExtractedText> value = new CompletableFuture<>();
final AndroidFuture<ExtractedText> future = new AndroidFuture<>();
try {
mIInputContext.getExtractedText(request, flags, ResultCallbacks.ofExtractedText(value));
mIInputContext.getExtractedText(request, flags, future);
} catch (RemoteException e) {
value.completeExceptionally(e);
future.completeExceptionally(e);
}
return value;
return future;
}
/**
@@ -479,19 +477,19 @@ public final class IInputContextInvoker {
* Invokes {@link IInputContext#requestCursorUpdates(int, IIntResultCallback)}.
*
* @param cursorUpdateMode {@code cursorUpdateMode} parameter to be passed.
* @return {@link CompletableFuture<Boolean>} that can be used to retrieve the invocation
* @return {@link AndroidFuture<Boolean>} that can be used to retrieve the invocation
* result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
public CompletableFuture<Boolean> requestCursorUpdates(int cursorUpdateMode) {
final CompletableFuture<Boolean> value = new CompletableFuture<>();
public AndroidFuture<Boolean> requestCursorUpdates(int cursorUpdateMode) {
final AndroidFuture<Boolean> future = new AndroidFuture<>();
try {
mIInputContext.requestCursorUpdates(cursorUpdateMode, ResultCallbacks.ofBoolean(value));
mIInputContext.requestCursorUpdates(cursorUpdateMode, future);
} catch (RemoteException e) {
value.completeExceptionally(e);
future.completeExceptionally(e);
}
return value;
return future;
}
/**
@@ -501,21 +499,20 @@ public final class IInputContextInvoker {
* @param inputContentInfo {@code inputContentInfo} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
* @param opts {@code opts} parameter to be passed.
* @return {@link CompletableFuture<Boolean>} that can be used to retrieve the invocation
* @return {@link AndroidFuture<Boolean>} that can be used to retrieve the invocation
* result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
public CompletableFuture<Boolean> commitContent(InputContentInfo inputContentInfo, int flags,
public AndroidFuture<Boolean> commitContent(InputContentInfo inputContentInfo, int flags,
Bundle opts) {
final CompletableFuture<Boolean> value = new CompletableFuture<>();
final AndroidFuture<Boolean> future = new AndroidFuture<>();
try {
mIInputContext.commitContent(inputContentInfo, flags, opts,
ResultCallbacks.ofBoolean(value));
mIInputContext.commitContent(inputContentInfo, flags, opts, future);
} catch (RemoteException e) {
value.completeExceptionally(e);
future.completeExceptionally(e);
}
return value;
return future;
}
/**

View File

@@ -19,10 +19,7 @@ package com.android.internal.inputmethod;
import android.net.Uri;
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputContentUriTokenResultCallback;
import com.android.internal.inputmethod.IVoidResultCallback;
import com.android.internal.infra.AndroidFuture;
/**
* Defines priviledged operations that only the current IME is allowed to call.
@@ -32,17 +29,17 @@ oneway interface IInputMethodPrivilegedOperations {
void setImeWindowStatusAsync(int vis, int backDisposition);
void reportStartInputAsync(in IBinder startInputToken);
void createInputContentUriToken(in Uri contentUri, in String packageName,
in IInputContentUriTokenResultCallback resultCallback);
in AndroidFuture future /* T=IBinder */);
void reportFullscreenModeAsync(boolean fullscreen);
void setInputMethod(String id, in IVoidResultCallback resultCallback);
void setInputMethod(String id, in AndroidFuture future /* T=Void */);
void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
in IVoidResultCallback resultCallback);
void hideMySoftInput(int flags, in IVoidResultCallback resultCallback);
void showMySoftInput(int flags, in IVoidResultCallback resultCallback);
in AndroidFuture future /* T=Void */);
void hideMySoftInput(int flags, in AndroidFuture future /* T=Void */);
void showMySoftInput(int flags, in AndroidFuture future /* T=Void */);
void updateStatusIconAsync(String packageName, int iconId);
void switchToPreviousInputMethod(in IBooleanResultCallback resultCallback);
void switchToNextInputMethod(boolean onlyCurrentIme, in IBooleanResultCallback resultCallback);
void shouldOfferSwitchingToNextInputMethod(in IBooleanResultCallback resultCallback);
void switchToPreviousInputMethod(in AndroidFuture future /* T=Boolean */);
void switchToNextInputMethod(boolean onlyCurrentIme, in AndroidFuture future /* T=Boolean */);
void shouldOfferSwitchingToNextInputMethod(in AndroidFuture future /* T=Boolean */);
void notifyUserActionAsync();
void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible);
}

View File

@@ -1,23 +0,0 @@
/*
* 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.view.inputmethod.SurroundingText;
oneway interface ISurroundingTextResultCallback {
void onResult(in SurroundingText result);
}

View File

@@ -1,24 +0,0 @@
/*
* 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 com.android.internal.inputmethod.ThrowableHolder;
oneway interface IVoidResultCallback {
void onResult();
void onError(in ThrowableHolder exception);
}

View File

@@ -28,9 +28,9 @@ import android.view.View;
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
/**
* A utility class to take care of boilerplate code around IPCs.
@@ -143,7 +143,7 @@ public final class InputMethodPrivilegedOperations {
/**
* Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String,
* IInputContentUriTokenResultCallback)}.
* AndroidFuture)}.
*
* @param contentUri Content URI to which a temporary read permission should be granted
* @param packageName Indicates what package needs to have a temporary read permission
@@ -157,10 +157,9 @@ public final class InputMethodPrivilegedOperations {
return null;
}
try {
final CompletableFuture<IInputContentUriToken> value = new CompletableFuture<>();
ops.createInputContentUriToken(contentUri, packageName,
ResultCallbacks.ofIInputContentUriToken(value));
return CompletableFutureUtil.getResult(value);
final AndroidFuture<IBinder> future = new AndroidFuture<>();
ops.createInputContentUriToken(contentUri, packageName, future);
return IInputContentUriToken.Stub.asInterface(CompletableFutureUtil.getResult(future));
} catch (RemoteException e) {
// For historical reasons, this error was silently ignored.
// Note that the caller already logs error so we do not need additional Log.e() here.
@@ -207,7 +206,7 @@ public final class InputMethodPrivilegedOperations {
}
/**
* Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String, IVoidResultCallback)}.
* Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String, AndroidFuture)}.
*
* @param id IME ID of the IME to switch to
* @see android.view.inputmethod.InputMethodInfo#getId()
@@ -219,9 +218,9 @@ public final class InputMethodPrivilegedOperations {
return;
}
try {
final CompletableFuture<Void> value = new CompletableFuture<>();
ops.setInputMethod(id, ResultCallbacks.ofVoid(value));
CompletableFutureUtil.getResult(value);
final AndroidFuture<Void> future = new AndroidFuture<>();
ops.setInputMethod(id, future);
CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -229,7 +228,7 @@ public final class InputMethodPrivilegedOperations {
/**
* Calls {@link IInputMethodPrivilegedOperations#setInputMethodAndSubtype(String,
* InputMethodSubtype, IVoidResultCallback)}
* InputMethodSubtype, AndroidFuture)}
*
* @param id IME ID of the IME to switch to
* @param subtype {@link InputMethodSubtype} to switch to
@@ -242,9 +241,9 @@ public final class InputMethodPrivilegedOperations {
return;
}
try {
final CompletableFuture<Void> value = new CompletableFuture<>();
ops.setInputMethodAndSubtype(id, subtype, ResultCallbacks.ofVoid(value));
CompletableFutureUtil.getResult(value);
final AndroidFuture<Void> future = new AndroidFuture<>();
ops.setInputMethodAndSubtype(id, subtype, future);
CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -264,16 +263,16 @@ public final class InputMethodPrivilegedOperations {
return;
}
try {
final CompletableFuture<Void> value = new CompletableFuture<>();
ops.hideMySoftInput(flags, ResultCallbacks.ofVoid(value));
CompletableFutureUtil.getResult(value);
final AndroidFuture<Void> future = new AndroidFuture<>();
ops.hideMySoftInput(flags, future);
CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, IVoidResultCallback)}
* Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, AndroidFuture)}
*
* @param flags additional operating flags
* @see android.view.inputmethod.InputMethodManager#SHOW_IMPLICIT
@@ -286,17 +285,16 @@ public final class InputMethodPrivilegedOperations {
return;
}
try {
final CompletableFuture<Void> value = new CompletableFuture<>();
ops.showMySoftInput(flags, ResultCallbacks.ofVoid(value));
CompletableFutureUtil.getResult(value);
final AndroidFuture<Void> future = new AndroidFuture<>();
ops.showMySoftInput(flags, future);
CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod(
* IBooleanResultCallback)}
* Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod(AndroidFuture)}
*
* @return {@code true} if handled
*/
@@ -307,8 +305,8 @@ public final class InputMethodPrivilegedOperations {
return false;
}
try {
final CompletableFuture<Boolean> value = new CompletableFuture<>();
ops.switchToPreviousInputMethod(ResultCallbacks.ofBoolean(value));
final AndroidFuture<Boolean> value = new AndroidFuture<>();
ops.switchToPreviousInputMethod(value);
return CompletableFutureUtil.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -330,9 +328,9 @@ public final class InputMethodPrivilegedOperations {
return false;
}
try {
final CompletableFuture<Boolean> value = new CompletableFuture<>();
ops.switchToNextInputMethod(onlyCurrentIme, ResultCallbacks.ofBoolean(value));
return CompletableFutureUtil.getResult(value);
final AndroidFuture<Boolean> future = new AndroidFuture<>();
ops.switchToNextInputMethod(onlyCurrentIme, future);
return CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -340,7 +338,7 @@ public final class InputMethodPrivilegedOperations {
/**
* Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod(
* IBooleanResultCallback)}
* AndroidFuture)}
*
* @return {@code true} if the IEM should offer a way to globally switch IME
*/
@@ -351,9 +349,9 @@ public final class InputMethodPrivilegedOperations {
return false;
}
try {
final CompletableFuture<Boolean> value = new CompletableFuture<>();
ops.shouldOfferSwitchingToNextInputMethod(ResultCallbacks.ofBoolean(value));
return CompletableFutureUtil.getResult(value);
final AndroidFuture<Boolean> future = new AndroidFuture<>();
ops.shouldOfferSwitchingToNextInputMethod(future);
return CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -40,6 +39,7 @@ import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.SurroundingText;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.view.IInputContext;
import java.lang.ref.WeakReference;
@@ -220,7 +220,10 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
}
@Override
public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
public void getTextAfterCursor(int length, int flags,
AndroidFuture future /* T=CharSequence */) {
@SuppressWarnings("unchecked")
final AndroidFuture<CharSequence> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
try {
@@ -238,12 +241,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
+ " result=" + result, e);
}
typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -251,7 +249,10 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
}
@Override
public void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback) {
public void getTextBeforeCursor(int length, int flags,
AndroidFuture future /* T=CharSequence */) {
@SuppressWarnings("unchecked")
final AndroidFuture<CharSequence> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
try {
@@ -269,12 +270,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
+ " result=" + result, e);
}
typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -282,7 +278,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
}
@Override
public void getSelectedText(int flags, ICharSequenceResultCallback callback) {
public void getSelectedText(int flags, AndroidFuture future /* T=CharSequence */) {
@SuppressWarnings("unchecked")
final AndroidFuture<CharSequence> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
try {
@@ -300,12 +298,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSelectedText", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
Log.w(TAG, "Failed to return the result to getSelectedText()."
+ " result=" + result, e);
}
typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -314,7 +307,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void getSurroundingText(int beforeLength, int afterLength, int flags,
ISurroundingTextResultCallback callback) {
AndroidFuture future /* T=SurroundingText */) {
@SuppressWarnings("unchecked")
final AndroidFuture<SurroundingText> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
try {
@@ -332,12 +327,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
Log.w(TAG, "Failed to return the result to getSurroundingText()."
+ " result=" + result, e);
}
typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -345,7 +335,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
}
@Override
public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
public void getCursorCapsMode(int reqModes, AndroidFuture future /* T=Integer */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Integer> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
try {
@@ -363,12 +355,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
+ " result=" + result, e);
}
typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -377,7 +364,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void getExtractedText(ExtractedTextRequest request, int flags,
IExtractedTextResultCallback callback) {
AndroidFuture future /* T=ExtractedText */) {
@SuppressWarnings("unchecked")
final AndroidFuture<ExtractedText> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
try {
@@ -395,12 +384,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getExtractedText", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
Log.w(TAG, "Failed to return the result to getExtractedText()."
+ " result=" + result, e);
}
typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -710,7 +694,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
}
@Override
public void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback) {
public void requestCursorUpdates(int cursorUpdateMode, AndroidFuture future /* T=Boolean */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Boolean> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
try {
@@ -722,12 +708,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
} else {
result = ic.requestCursorUpdates(cursorUpdateMode);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
+ " result=" + result, e);
}
typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -736,7 +717,9 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts,
IBooleanResultCallback callback) {
AndroidFuture future /* T=Boolean */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Boolean> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
try {
@@ -754,12 +737,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
result = ic.commitContent(inputContentInfo, flags, opts);
}
}
try {
callback.onResult(result);
} catch (RemoteException e) {
Log.w(TAG, "Failed to return the result to commitContent()."
+ " result=" + result, e);
}
typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}

View File

@@ -1,275 +0,0 @@
/*
* 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.BinderThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.SurroundingText;
import java.util.concurrent.CompletableFuture;
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 CompletableFuture}.
*/
public final class ResultCallbacks {
/**
* Not intended to be instantiated.
*/
private ResultCallbacks() {
}
private static final class LightweightThrowable extends RuntimeException {
LightweightThrowable(@Nullable ThrowableHolder throwableHolder) {
super(throwableHolder != null ? throwableHolder.getMessage() : null,
null, false, false);
}
}
@AnyThread
@Nullable
private static <T> T unwrap(@NonNull AtomicReference<T> atomicRef) {
// Only the first caller will receive the non-null original object.
return atomicRef.getAndSet(null);
}
/**
* Creates {@link IIntResultCallback.Stub} that is to set {@link CompletableFuture<Integer>}
* when receiving the result.
*
* @param value {@link CompletableFuture<Integer>} 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 ofInteger(@NonNull CompletableFuture<Integer> value) {
final AtomicReference<CompletableFuture<Integer>> atomicRef = new AtomicReference<>(value);
return new IIntResultCallback.Stub() {
@BinderThread
@Override
public void onResult(int result) {
final CompletableFuture<Integer> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.complete(result);
}
@BinderThread
@Override
public void onError(ThrowableHolder throwableHolder) {
final CompletableFuture<Integer> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.completeExceptionally(new LightweightThrowable(throwableHolder));
}
};
}
/**
* Creates {@link ICharSequenceResultCallback.Stub} that is to set
* {@link CompletableFuture<CharSequence>} when receiving the result.
*
* @param value {@link CompletableFuture<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 ofCharSequence(
@NonNull CompletableFuture<CharSequence> value) {
final AtomicReference<CompletableFuture<CharSequence>> atomicRef =
new AtomicReference<>(value);
return new ICharSequenceResultCallback.Stub() {
@BinderThread
@Override
public void onResult(CharSequence result) {
final CompletableFuture<CharSequence> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.complete(result);
}
};
}
/**
* Creates {@link IExtractedTextResultCallback.Stub} that is to set
* {@link CompletableFuture<ExtractedText>} when receiving the result.
*
* @param value {@link CompletableFuture<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 ofExtractedText(
@NonNull CompletableFuture<ExtractedText> value) {
final AtomicReference<CompletableFuture<ExtractedText>> atomicRef =
new AtomicReference<>(value);
return new IExtractedTextResultCallback.Stub() {
@BinderThread
@Override
public void onResult(android.view.inputmethod.ExtractedText result) {
final CompletableFuture<ExtractedText> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.complete(result);
}
};
}
/**
* Creates {@link ISurroundingTextResultCallback.Stub} that is to set
* {@link CompletableFuture<SurroundingText>} when receiving the result.
*
* @param value {@link CompletableFuture<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 ofSurroundingText(
@NonNull CompletableFuture<SurroundingText> value) {
final AtomicReference<CompletableFuture<SurroundingText>> atomicRef =
new AtomicReference<>(value);
return new ISurroundingTextResultCallback.Stub() {
@BinderThread
@Override
public void onResult(android.view.inputmethod.SurroundingText result) {
final CompletableFuture<SurroundingText> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.complete(result);
}
};
}
/**
* Creates {@link IBooleanResultCallback.Stub} that is to set {@link CompletableFuture<Boolean>}
* when receiving the result.
*
* @param value {@link CompletableFuture<Boolean>} to be set when receiving the result.
* @return {@link IBooleanResultCallback.Stub} that can be passed as a binder IPC parameter.
*/
@AnyThread
public static IBooleanResultCallback.Stub ofBoolean(@NonNull CompletableFuture<Boolean> value) {
final AtomicReference<CompletableFuture<Boolean>> atomicRef = new AtomicReference<>(value);
return new IBooleanResultCallback.Stub() {
@BinderThread
@Override
public void onResult(boolean result) {
final CompletableFuture<Boolean> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.complete(result);
}
@BinderThread
@Override
public void onError(ThrowableHolder throwableHolder) {
final CompletableFuture<Boolean> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.completeExceptionally(new LightweightThrowable(throwableHolder));
}
};
}
/**
* Creates {@link IVoidResultCallback.Stub} that is to set {@link CompletableFuture<Void>} when
* receiving the result.
*
* @param value {@link CompletableFuture<Void>} to be set when receiving the result.
* @return {@link IVoidResultCallback.Stub} that can be passed as a binder IPC parameter.
*/
@AnyThread
public static IVoidResultCallback.Stub ofVoid(@NonNull CompletableFuture<Void> value) {
final AtomicReference<CompletableFuture<Void>> atomicRef = new AtomicReference<>(value);
return new IVoidResultCallback.Stub() {
@BinderThread
@Override
public void onResult() {
final CompletableFuture<Void> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.complete(null);
}
@BinderThread
@Override
public void onError(ThrowableHolder throwableHolder) {
final CompletableFuture<Void> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.completeExceptionally(new LightweightThrowable(throwableHolder));
}
};
}
/**
* Creates {@link IInputContentUriTokenResultCallback.Stub} that is to set
* {@link CompletableFuture<IInputContentUriToken>} when receiving the result.
*
* @param value {@link CompletableFuture<IInputContentUriToken>} to be set when receiving the
* result.
* @return {@link IInputContentUriTokenResultCallback.Stub} that can be passed as a binder IPC
* parameter.
*/
@AnyThread
public static IInputContentUriTokenResultCallback.Stub ofIInputContentUriToken(
@NonNull CompletableFuture<IInputContentUriToken> value) {
final AtomicReference<CompletableFuture<IInputContentUriToken>>
atomicRef = new AtomicReference<>(value);
return new IInputContentUriTokenResultCallback.Stub() {
@BinderThread
@Override
public void onResult(IInputContentUriToken result) {
final CompletableFuture<IInputContentUriToken> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.complete(result);
}
@BinderThread
@Override
public void onError(ThrowableHolder throwableHolder) {
final CompletableFuture<IInputContentUriToken> value = unwrap(atomicRef);
if (value == null) {
return;
}
value.completeExceptionally(new LightweightThrowable(throwableHolder));
}
};
}
}

View File

@@ -23,11 +23,7 @@ import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputContentInfo;
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.ICharSequenceResultCallback;
import com.android.internal.inputmethod.IExtractedTextResultCallback;
import com.android.internal.inputmethod.IIntResultCallback;
import com.android.internal.inputmethod.ISurroundingTextResultCallback;
import com.android.internal.infra.AndroidFuture;
/**
* Interface from an input method to the application, allowing it to perform
@@ -35,14 +31,14 @@ import com.android.internal.inputmethod.ISurroundingTextResultCallback;
* {@hide}
*/
oneway interface IInputContext {
void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback);
void getTextBeforeCursor(int length, int flags, in AndroidFuture future /* T=CharSequence */);
void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback);
void getTextAfterCursor(int length, int flags, in AndroidFuture future /* T=CharSequence */);
void getCursorCapsMode(int reqModes, IIntResultCallback callback);
void getCursorCapsMode(int reqModes, in AndroidFuture future /* T=Integer */);
void getExtractedText(in ExtractedTextRequest request, int flags,
IExtractedTextResultCallback callback);
in AndroidFuture future /* T=ExtractedText */);
void deleteSurroundingText(int beforeLength, int afterLength);
void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
@@ -50,7 +46,7 @@ import com.android.internal.inputmethod.ISurroundingTextResultCallback;
void setComposingText(CharSequence text, int newCursorPosition);
void finishComposingText();
void commitText(CharSequence text, int newCursorPosition);
void commitCompletion(in CompletionInfo completion);
@@ -58,34 +54,34 @@ import com.android.internal.inputmethod.ISurroundingTextResultCallback;
void commitCorrection(in CorrectionInfo correction);
void setSelection(int start, int end);
void performEditorAction(int actionCode);
void performContextMenuAction(int id);
void beginBatchEdit();
void endBatchEdit();
void sendKeyEvent(in KeyEvent event);
void clearMetaKeyStates(int states);
void performSpellCheck();
void performPrivateCommand(String action, in Bundle data);
void setComposingRegion(int start, int end);
void getSelectedText(int flags, ICharSequenceResultCallback callback);
void getSelectedText(int flags, in AndroidFuture future /* T=CharSequence */);
void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback);
void requestCursorUpdates(int cursorUpdateMode, in AndroidFuture future /* T=Boolean */);
void commitContent(in InputContentInfo inputContentInfo, int flags, in Bundle opts,
IBooleanResultCallback callback);
in AndroidFuture future /* T=Boolean */);
void getSurroundingText(int beforeLength, int afterLength, int flags,
ISurroundingTextResultCallback callback);
in AndroidFuture future /* T=SurroundingText */);
void setImeConsumesInput(boolean imeConsumesInput);
}

View File

@@ -152,12 +152,9 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.PackageMonitor;
import com.android.internal.inputmethod.CallbackUtils;
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputContentUriTokenResultCallback;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.IVoidResultCallback;
import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
@@ -5842,9 +5839,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
public void createInputContentUriToken(Uri contentUri, String packageName,
IInputContentUriTokenResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> mImms.createInputContentUriToken(mToken, contentUri, packageName));
AndroidFuture future /* T=IBinder */) {
@SuppressWarnings("unchecked")
final AndroidFuture<IBinder> typedFuture = future;
try {
typedFuture.complete(mImms.createInputContentUriToken(
mToken, contentUri, packageName).asBinder());
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
}
}
@BinderThread
@@ -5855,28 +5858,55 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
public void setInputMethod(String id, IVoidResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> mImms.setInputMethod(mToken, id));
public void setInputMethod(String id, AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
mImms.setInputMethod(mToken, id);
typedFuture.complete(null);
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
}
}
@BinderThread
@Override
public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype,
IVoidResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> mImms.setInputMethodAndSubtype(mToken, id, subtype));
AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
mImms.setInputMethodAndSubtype(mToken, id, subtype);
typedFuture.complete(null);
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
}
}
@BinderThread
@Override
public void hideMySoftInput(int flags, IVoidResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> mImms.hideMySoftInput(mToken, flags));
public void hideMySoftInput(int flags, AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
mImms.hideMySoftInput(mToken, flags);
typedFuture.complete(null);
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
}
}
@BinderThread
@Override
public void showMySoftInput(int flags, IVoidResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> mImms.showMySoftInput(mToken, flags));
public void showMySoftInput(int flags, AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
mImms.showMySoftInput(mToken, flags);
typedFuture.complete(null);
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
}
}
@BinderThread
@@ -5887,24 +5917,39 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
public void switchToPreviousInputMethod(IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> mImms.switchToPreviousInputMethod(mToken));
public void switchToPreviousInputMethod(AndroidFuture future /* T=Boolean */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Boolean> typedFuture = future;
try {
typedFuture.complete(mImms.switchToPreviousInputMethod(mToken));
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
}
}
@BinderThread
@Override
public void switchToNextInputMethod(boolean onlyCurrentIme,
IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
AndroidFuture future /* T=Boolean */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Boolean> typedFuture = future;
try {
typedFuture.complete(mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
}
}
@BinderThread
@Override
public void shouldOfferSwitchingToNextInputMethod(
IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> mImms.shouldOfferSwitchingToNextInputMethod(mToken));
public void shouldOfferSwitchingToNextInputMethod(AndroidFuture future /* T=Boolean */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Boolean> typedFuture = future;
try {
typedFuture.complete(mImms.shouldOfferSwitchingToNextInputMethod(mToken));
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
}
}
@BinderThread