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:
@@ -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) { }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user