Merge "Async startInputOrWindowGainedFocus" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ecfc497460
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user