Merge "Make IInputMethodManager to oneway (5/N)"

This commit is contained in:
Wilson Wu
2020-12-16 09:33:42 +00:00
committed by Android (Google) Code Review
8 changed files with 239 additions and 91 deletions

View File

@@ -25,6 +25,9 @@ import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.inputmethod.Completable;
import com.android.internal.inputmethod.ResultCallbacks;
import java.io.PrintWriter;
/**
@@ -32,7 +35,9 @@ import java.io.PrintWriter;
*/
class ImeTracingClientImpl extends ImeTracing {
ImeTracingClientImpl() throws ServiceNotFoundException, RemoteException {
sEnabled = mService.isImeTraceEnabled();
final Completable.Boolean value = Completable.createBoolean();
mService.isImeTraceEnabled(ResultCallbacks.of(value));
sEnabled = Completable.getResult(value);
}
@Override

View File

@@ -1747,8 +1747,14 @@ public final class InputMethodManager {
try {
Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags);
return mService.showSoftInput(
mClient, view.getWindowToken(), flags, resultReceiver);
final Completable.Boolean value = Completable.createBoolean();
mService.showSoftInput(
mClient,
view.getWindowToken(),
flags,
resultReceiver,
ResultCallbacks.of(value));
return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1775,8 +1781,14 @@ public final class InputMethodManager {
Log.w(TAG, "No current root view, ignoring showSoftInputUnchecked()");
return;
}
final Completable.Boolean value = Completable.createBoolean();
mService.showSoftInput(
mClient, mCurRootView.getView().getWindowToken(), flags, resultReceiver);
mClient,
mCurRootView.getView().getWindowToken(),
flags,
resultReceiver,
ResultCallbacks.of(value));
Completable.getResult(value); // ignore the result
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1849,7 +1861,10 @@ public final class InputMethodManager {
}
try {
return mService.hideSoftInput(mClient, windowToken, flags, resultReceiver);
final Completable.Boolean value = Completable.createBoolean();
mService.hideSoftInput(
mClient, windowToken, flags, resultReceiver, ResultCallbacks.of(value));
return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2184,8 +2199,14 @@ public final class InputMethodManager {
return;
}
try {
final Completable.Boolean value = Completable.createBoolean();
mService.hideSoftInput(
mClient, mCurRootView.getView().getWindowToken(), HIDE_NOT_ALWAYS, null);
mClient,
mCurRootView.getView().getWindowToken(),
HIDE_NOT_ALWAYS,
null,
ResultCallbacks.of(value));
Completable.getResult(value); // ignore the result
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2920,7 +2941,9 @@ public final class InputMethodManager {
@TestApi
public boolean isInputMethodPickerShown() {
try {
return mService.isInputMethodPickerShownForTest();
final Completable.Boolean value = Completable.createBoolean();
mService.isInputMethodPickerShownForTest(ResultCallbacks.of(value));
return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -22,6 +22,7 @@ import android.os.RemoteException;
import com.android.internal.view.InputBindResult;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
/**
@@ -62,4 +63,30 @@ public final class CallbackUtils {
callback.onResult(result);
} catch (RemoteException ignored) { }
}
/**
* A utility method using given {@link IBooleanResultCallback} to callback the result.
*
* @param callback {@link IInputBindResultResultCallback} 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) { }
}
}

View File

@@ -0,0 +1,24 @@
/*
* 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

@@ -193,4 +193,39 @@ public final class ResultCallbacks {
}
};
}
/**
* Creates {@link IBooleanResultCallback.Stub} that is to set {@link Completable.Boolean} when
* receiving the result.
*
* @param value {@link Completable.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 of(@NonNull Completable.Boolean value) {
final AtomicReference<WeakReference<Completable.Boolean>>
atomicRef = new AtomicReference<>(new WeakReference<>(value));
return new IBooleanResultCallback.Stub() {
@BinderThread
@Override
public void onResult(boolean result) {
final Completable.Boolean value = unwrap(atomicRef);
if (value == null) {
return;
}
value.onComplete(result);
}
@BinderThread
@Override
public void onError(ThrowableHolder throwableHolder) {
final Completable.Boolean value = unwrap(atomicRef);
if (value == null) {
return;
}
value.onError(throwableHolder);
}
};
}
}

View File

@@ -24,6 +24,7 @@ import android.view.inputmethod.EditorInfo;
import com.android.internal.view.InputBindResult;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.IInputBindResultResultCallback;
/**
@@ -42,10 +43,10 @@ interface IInputMethodManager {
boolean allowsImplicitlySelectedSubtypes);
InputMethodSubtype getLastInputMethodSubtype();
boolean showSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
in ResultReceiver resultReceiver);
boolean hideSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
in ResultReceiver resultReceiver);
void showSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
in ResultReceiver resultReceiver, in IBooleanResultCallback resultCallback);
void hideSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
in ResultReceiver resultReceiver, in IBooleanResultCallback resultCallback);
// If windowToken is null, this just does startInput(). Otherwise this reports that a window
// has gained focus, and if 'attribute' is non-null then also does startInput.
// @NonNull
@@ -64,7 +65,7 @@ interface IInputMethodManager {
void showInputMethodPickerFromSystem(in IInputMethodClient client, int auxiliarySubtypeMode,
int displayId);
void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
boolean isInputMethodPickerShownForTest();
void isInputMethodPickerShownForTest(in IBooleanResultCallback resultCallback);
InputMethodSubtype getCurrentInputMethodSubtype();
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage.
@@ -80,7 +81,7 @@ interface IInputMethodManager {
/** Remove the IME surface. Requires passing the currently focused window. */
void removeImeSurfaceFromWindow(in IBinder windowToken);
void startProtoDump(in byte[] protoDump, int source, String where);
boolean isImeTraceEnabled();
void isImeTraceEnabled(in IBooleanResultCallback resultCallback);
// Starts an ime trace.
void startImeTrace();

View File

@@ -159,6 +159,7 @@ 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.inputmethod.IInputBindResultResultCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
@@ -3150,41 +3151,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#showSoftInput");
synchronized (mMethodMap) {
if (!calledFromValidUserLocked()) {
return false;
}
final long ident = Binder.clearCallingIdentity();
try {
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
return false;
}
public void showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#showSoftInput");
synchronized (mMethodMap) {
if (!calledFromValidUserLocked()) {
return false;
}
final long ident = Binder.clearCallingIdentity();
try {
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
throw new IllegalArgumentException(
"unknown client " + client.asBinder());
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
return false;
}
}
if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
return showCurrentInputLocked(windowToken, flags, resultReceiver,
SoftInputShowHideReason.SHOW_SOFT_INPUT);
} finally {
Binder.restoreCallingIdentity(ident);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
return showCurrentInputLocked(windowToken, flags, resultReceiver,
SoftInputShowHideReason.SHOW_SOFT_INPUT);
} finally {
Binder.restoreCallingIdentity(ident);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
});
}
@BinderThread
@@ -3266,44 +3270,49 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#hideSoftInput");
synchronized (mMethodMap) {
if (!calledFromValidUserLocked()) {
return false;
}
final long ident = Binder.clearCallingIdentity();
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideSoftInput");
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
if (DEBUG) {
Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
}
return false;
}
public void hideSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> {
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#hideSoftInput");
synchronized (mMethodMap) {
if (!InputMethodManagerService.this.calledFromValidUserLocked()) {
return false;
}
final long ident = Binder.clearCallingIdentity();
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideSoftInput");
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
throw new IllegalArgumentException(
"unknown client " + client.asBinder());
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
if (DEBUG) {
Slog.w(TAG,
"Ignoring hideSoftInput of uid " + uid + ": " + client);
}
return false;
}
}
if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
return hideCurrentInputLocked(windowToken, flags, resultReceiver,
SoftInputShowHideReason.HIDE_SOFT_INPUT);
} finally {
Binder.restoreCallingIdentity(ident);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
return InputMethodManagerService.this.hideCurrentInputLocked(windowToken,
flags, resultReceiver,
SoftInputShowHideReason.HIDE_SOFT_INPUT);
} finally {
Binder.restoreCallingIdentity(ident);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
}
});
}
boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
@@ -3726,9 +3735,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
}
public boolean isInputMethodPickerShownForTest() {
/**
* A test API for CTS to make sure that the input method menu is showing.
*
* @param resultCallback {@code true} while the input method menu is showing UI.
*/
public void isInputMethodPickerShownForTest(IBooleanResultCallback resultCallback) {
synchronized(mMethodMap) {
return mMenuController.isisInputMethodPickerShownForTestLocked();
CallbackUtils.onResult(
resultCallback, mMenuController::isisInputMethodPickerShownForTestLocked);
}
}
@@ -4120,8 +4135,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
public boolean isImeTraceEnabled() {
return ImeTracing.getInstance().isEnabled();
public void isImeTraceEnabled(IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> ImeTracing.getInstance().isEnabled());
}
@BinderThread

View File

@@ -73,6 +73,7 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.CallbackUtils;
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.IInputBindResultResultCallback;
import com.android.internal.inputmethod.IMultiClientInputMethod;
import com.android.internal.inputmethod.IMultiClientInputMethodPrivilegedOperations;
@@ -1501,7 +1502,15 @@ public final class MultiClientInputMethodManagerService {
@BinderThread
@Override
public boolean showSoftInput(
public void showSoftInput(
IInputMethodClient client, IBinder token, int flags,
ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> showSoftInputInternal(client, token, flags, resultReceiver));
}
@BinderThread
private boolean showSoftInputInternal(
IInputMethodClient client, IBinder token, int flags,
ResultReceiver resultReceiver) {
final int callingUid = Binder.getCallingUid();
@@ -1548,7 +1557,16 @@ public final class MultiClientInputMethodManagerService {
@BinderThread
@Override
public boolean hideSoftInput(
public void hideSoftInput(
IInputMethodClient client, IBinder windowToken, int flags,
ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> hideSoftInputInternal(client, windowToken, flags, resultReceiver));
}
@BinderThread
private boolean hideSoftInputInternal(
IInputMethodClient client, IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
final int callingUid = Binder.getCallingUid();
@@ -1768,9 +1786,9 @@ public final class MultiClientInputMethodManagerService {
@BinderThread
@Override
public boolean isInputMethodPickerShownForTest() {
public void isInputMethodPickerShownForTest(IBooleanResultCallback resultCallback) {
reportNotSupported();
return false;
CallbackUtils.onResult(resultCallback, () -> false);
}
@BinderThread
@@ -1834,8 +1852,8 @@ public final class MultiClientInputMethodManagerService {
@BinderThread
@Override
public boolean isImeTraceEnabled() {
return false;
public void isImeTraceEnabled(IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> false);
}
@BinderThread