Merge "Async startInputOrWindowGainedFocus" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-04-26 19:06:26 +00:00
committed by Android (Google) Code Review
5 changed files with 157 additions and 69 deletions

View File

@@ -265,6 +265,14 @@ public final class InputMethodManager {
private static final int NOT_A_SUBTYPE_ID = -1;
/**
* {@code true} to try to avoid blocking apps' UI thread by sending
* {@link StartInputReason#WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION} and
* {@link StartInputReason#WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION} in a truly asynchronous
* way. {@code false} to go back to the previous synchronous semantics.
*/
private static final boolean USE_REPORT_WINDOW_GAINED_FOCUS_ASYNC = false;
/**
* A constant that represents Voice IME.
*
@@ -689,20 +697,29 @@ public final class InputMethodManager {
Log.v(TAG, "Reporting focus gain, without startInput"
+ ", nextFocusIsServedView=" + nextFocusHasConnection);
}
final int startInputReason =
nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
: WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
final Completable.InputBindResult value = Completable.createInputBindResult();
mService.startInputOrWindowGainedFocus(
startInputReason, mClient,
focusedView.getWindowToken(), startInputFlags, softInputMode,
windowFlags,
null,
null,
0 /* missingMethodFlags */,
mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
ResultCallbacks.of(value));
Completable.getResult(value); // ignore the result
if (USE_REPORT_WINDOW_GAINED_FOCUS_ASYNC) {
mService.reportWindowGainedFocusAsync(
nextFocusHasConnection, mClient, focusedView.getWindowToken(),
startInputFlags, softInputMode, windowFlags,
mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
} else {
final int startInputReason = nextFocusHasConnection
? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
: WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
final Completable.InputBindResult value =
Completable.createInputBindResult();
mService.startInputOrWindowGainedFocus(
startInputReason, mClient,
focusedView.getWindowToken(), startInputFlags, softInputMode,
windowFlags,
null,
null,
0 /* missingMethodFlags */,
mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
ResultCallbacks.of(value));
Completable.getResult(value); // ignore the result
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1087,6 +1104,11 @@ public final class InputMethodManager {
public void setImeTraceEnabled(boolean enabled) {
ImeTracing.getInstance().setEnabled(enabled);
}
@Override
public void throwExceptionFromSystem(String message) {
throw new RuntimeException(message);
}
};
final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);

View File

@@ -30,4 +30,5 @@ oneway interface IInputMethodClient {
void reportFullscreenMode(boolean fullscreen);
void updateActivityViewToScreenMatrix(int bindSequence, in float[] matrixValues);
void setImeTraceEnabled(boolean enabled);
void throwExceptionFromSystem(String message);
}

View File

@@ -68,6 +68,12 @@ interface IInputMethodManager {
int unverifiedTargetSdkVersion,
in IInputBindResultResultCallback inputBindResult);
oneway void reportWindowGainedFocusAsync(
boolean nextFocusHasConnection, in IInputMethodClient client, in IBinder windowToken,
/* @StartInputFlags */ int startInputFlags,
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, int unverifiedTargetSdkVersion);
oneway void showInputMethodPickerFromClient(in IInputMethodClient client,
int auxiliarySubtypeMode, in IVoidResultCallback resultCallback);
oneway void showInputMethodPickerFromSystem(in IInputMethodClient client,

View File

@@ -3353,6 +3353,28 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return res;
}
@NonNull
@Override
public void reportWindowGainedFocusAsync(
boolean nextFocusHasConnection, IInputMethodClient client, IBinder windowToken,
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags, int unverifiedTargetSdkVersion) {
final int startInputReason = nextFocusHasConnection
? StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
: StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
try {
startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
startInputFlags, softInputMode, windowFlags, null /* attribute */,
null /* inputContext */, 0 /* missingMethods */, unverifiedTargetSdkVersion);
} catch (Throwable t) {
if (client != null) {
try {
client.throwExceptionFromSystem(t.getMessage());
} catch (RemoteException ignore) { }
}
}
}
@NonNull
@Override
public void startInputOrWindowGainedFocus(
@@ -3361,62 +3383,72 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
@MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion,
IInputBindResultResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () -> {
if (windowToken == null) {
Slog.e(TAG, "windowToken cannot be null.");
CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () ->
startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
startInputFlags, softInputMode, windowFlags, attribute, inputContext,
missingMethods, unverifiedTargetSdkVersion));
}
@NonNull
private InputBindResult startInputOrWindowGainedFocusInternal(
@StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags, @Nullable EditorInfo attribute, @Nullable IInputContext inputContext,
@MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
if (windowToken == null) {
Slog.e(TAG, "windowToken cannot be null.");
return InputBindResult.NULL;
}
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"IMMS.startInputOrWindowGainedFocus");
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#startInputOrWindowGainedFocus");
final int callingUserId = UserHandle.getCallingUserId();
final int userId;
if (attribute != null && attribute.targetInputMethodUser != null
&& attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
mContext.enforceCallingPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
"Using EditorInfo.targetInputMethodUser requires"
+ " INTERACT_ACROSS_USERS_FULL.");
userId = attribute.targetInputMethodUser.getIdentifier();
if (!mUserManagerInternal.isUserRunning(userId)) {
// There is a chance that we hit here because of race condition. Let's just
// return an error code instead of crashing the caller process, which at
// least has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an
// important process.
Slog.e(TAG, "User #" + userId + " is not running.");
return InputBindResult.INVALID_USER;
}
} else {
userId = callingUserId;
}
final InputBindResult result;
synchronized (mMethodMap) {
final long ident = Binder.clearCallingIdentity();
try {
result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
client, windowToken, startInputFlags, softInputMode, windowFlags,
attribute, inputContext, missingMethods, unverifiedTargetSdkVersion,
userId);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
if (result == null) {
// This must never happen, but just in case.
Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
+ InputMethodDebug.startInputReasonToString(startInputReason)
+ " windowFlags=#" + Integer.toHexString(windowFlags)
+ " editorInfo=" + attribute);
return InputBindResult.NULL;
}
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"IMMS.startInputOrWindowGainedFocus");
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#startInputOrWindowGainedFocus");
final int callingUserId = UserHandle.getCallingUserId();
final int userId;
if (attribute != null && attribute.targetInputMethodUser != null
&& attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
mContext.enforceCallingPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
"Using EditorInfo.targetInputMethodUser requires"
+ " INTERACT_ACROSS_USERS_FULL.");
userId = attribute.targetInputMethodUser.getIdentifier();
if (!mUserManagerInternal.isUserRunning(userId)) {
// There is a chance that we hit here because of race condition. Let's just
// return an error code instead of crashing the caller process, which at
// least has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an
// important process.
Slog.e(TAG, "User #" + userId + " is not running.");
return InputBindResult.INVALID_USER;
}
} else {
userId = callingUserId;
}
final InputBindResult result;
synchronized (mMethodMap) {
final long ident = Binder.clearCallingIdentity();
try {
result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
client, windowToken, startInputFlags, softInputMode, windowFlags,
attribute, inputContext, missingMethods, unverifiedTargetSdkVersion,
userId);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
if (result == null) {
// This must never happen, but just in case.
Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
+ InputMethodDebug.startInputReasonToString(startInputReason)
+ " windowFlags=#" + Integer.toHexString(windowFlags)
+ " editorInfo=" + attribute);
return InputBindResult.NULL;
}
return result;
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
});
return result;
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
@NonNull

View File

@@ -1625,6 +1625,33 @@ public final class MultiClientInputMethodManagerService {
}
}
@BinderThread
@Override
public void reportWindowGainedFocusAsync(
boolean nextFocusHasConnection,
@Nullable IInputMethodClient client,
@Nullable IBinder windowToken,
@StartInputFlags int startInputFlags,
@SoftInputModeFlags int softInputMode,
int windowFlags,
int unverifiedTargetSdkVersion) {
final int startInputReason = nextFocusHasConnection
? StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
: StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
try {
startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
startInputFlags, softInputMode, windowFlags, null /* editorInfo */,
null /* inputContext */, 0 /* missingMethods */,
unverifiedTargetSdkVersion);
} catch (Throwable t) {
if (client != null) {
try {
client.throwExceptionFromSystem(t.getMessage());
} catch (RemoteException ignore) { }
}
}
}
@BinderThread
@Override
public void startInputOrWindowGainedFocus(
@@ -1641,8 +1668,8 @@ public final class MultiClientInputMethodManagerService {
IInputBindResultResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () ->
startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
startInputFlags, softInputMode, windowFlags, editorInfo, inputContext,
missingMethods, unverifiedTargetSdkVersion));
startInputFlags, softInputMode, windowFlags, editorInfo, inputContext,
missingMethods, unverifiedTargetSdkVersion));
}
@BinderThread