Merge "Make IInputMethodManager to oneway (3/N)"
This commit is contained in:
@@ -88,8 +88,10 @@ import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
|
||||
import android.view.autofill.AutofillManager;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.inputmethod.Completable;
|
||||
import com.android.internal.inputmethod.InputMethodDebug;
|
||||
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
|
||||
import com.android.internal.inputmethod.ResultCallbacks;
|
||||
import com.android.internal.inputmethod.StartInputFlags;
|
||||
import com.android.internal.inputmethod.StartInputReason;
|
||||
import com.android.internal.inputmethod.UnbindReason;
|
||||
@@ -666,6 +668,7 @@ public final class InputMethodManager {
|
||||
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,
|
||||
@@ -673,7 +676,9 @@ public final class InputMethodManager {
|
||||
null,
|
||||
null,
|
||||
0 /* missingMethodFlags */,
|
||||
mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
|
||||
mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
|
||||
ResultCallbacks.of(value));
|
||||
Completable.getResult(value); // ignore the result
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -2039,10 +2044,13 @@ public final class InputMethodManager {
|
||||
if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
|
||||
+ ic + " tba=" + tba + " startInputFlags="
|
||||
+ InputMethodDebug.startInputFlagsToString(startInputFlags));
|
||||
res = mService.startInputOrWindowGainedFocus(
|
||||
final Completable.InputBindResult value = Completable.createInputBindResult();
|
||||
mService.startInputOrWindowGainedFocus(
|
||||
startInputReason, mClient, windowGainingFocus, startInputFlags,
|
||||
softInputMode, windowFlags, tba, servedContext, missingMethodFlags,
|
||||
view.getContext().getApplicationInfo().targetSdkVersion);
|
||||
view.getContext().getApplicationInfo().targetSdkVersion,
|
||||
ResultCallbacks.of(value));
|
||||
res = Completable.getResult(value);
|
||||
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
|
||||
if (res == null) {
|
||||
Log.wtf(TAG, "startInputOrWindowGainedFocus must not return"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.NonNull;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.view.InputBindResult;
|
||||
|
||||
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 IInputBindResultResultCallback} to callback the
|
||||
* {@link InputBindResult}.
|
||||
*
|
||||
* @param callback {@link IInputBindResultResultCallback} to be called back.
|
||||
* @param resultSupplier the supplier from which {@link InputBindResult} is provided.
|
||||
*/
|
||||
@AnyThread
|
||||
public static void onResult(@NonNull IInputBindResultResultCallback callback,
|
||||
@NonNull Supplier<InputBindResult> resultSupplier) {
|
||||
try {
|
||||
callback.onResult(resultSupplier.get());
|
||||
} catch (RemoteException ignored) { }
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,16 @@ public final class Completable {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks the calling thread until this object becomes ready to return the value.
|
||||
*/
|
||||
@AnyThread
|
||||
public void await() {
|
||||
try {
|
||||
mLatch.await();
|
||||
} catch (InterruptedException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,6 +259,13 @@ public final class Completable {
|
||||
return new Completable.SurroundingText();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an instance of {@link Completable.InputBindResult}.
|
||||
*/
|
||||
public static Completable.InputBindResult createInputBindResult() {
|
||||
return new Completable.InputBindResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Completable object of {@link java.lang.Boolean}.
|
||||
*/
|
||||
@@ -277,6 +294,18 @@ public final class Completable {
|
||||
public static final class InputBindResult
|
||||
extends Values<com.android.internal.view.InputBindResult> { }
|
||||
|
||||
/**
|
||||
* Await the result by the {@link Completable.Values}.
|
||||
*
|
||||
* @return the result once {@link ValueBase#onComplete()}
|
||||
*/
|
||||
@AnyThread
|
||||
@Nullable
|
||||
public static <T> T getResult(@NonNull Completable.Values<T> value) {
|
||||
value.await();
|
||||
return value.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Await the result by the {@link Completable.Int}, and log it if there is no result after
|
||||
* given timeout.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.view.InputBindResult;
|
||||
|
||||
oneway interface IInputBindResultResultCallback {
|
||||
void onResult(in InputBindResult result);
|
||||
}
|
||||
@@ -21,6 +21,8 @@ import android.annotation.BinderThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import com.android.internal.view.InputBindResult;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -154,4 +156,31 @@ public final class ResultCallbacks {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link IInputBindResultResultCallback.Stub} that is to set
|
||||
* {@link Completable.InputBindResult} when receiving the result.
|
||||
*
|
||||
* @param value {@link Completable.InputBindResult} to be set when receiving the result.
|
||||
* @return {@link IInputBindResultResultCallback.Stub} that can be passed as a binder IPC
|
||||
* parameter.
|
||||
*/
|
||||
@AnyThread
|
||||
public static IInputBindResultResultCallback.Stub of(
|
||||
@NonNull Completable.InputBindResult value) {
|
||||
final AtomicReference<WeakReference<Completable.InputBindResult>>
|
||||
atomicRef = new AtomicReference<>(new WeakReference<>(value));
|
||||
|
||||
return new IInputBindResultResultCallback.Stub() {
|
||||
@BinderThread
|
||||
@Override
|
||||
public void onResult(InputBindResult result) {
|
||||
final Completable.InputBindResult value = unwrap(atomicRef);
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
value.onComplete(result);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.IInputBindResultResultCallback;
|
||||
|
||||
/**
|
||||
* Public interface to the global input method manager, used by all client
|
||||
@@ -48,14 +49,15 @@ interface IInputMethodManager {
|
||||
// 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
|
||||
InputBindResult startInputOrWindowGainedFocus(
|
||||
void startInputOrWindowGainedFocus(
|
||||
/* @StartInputReason */ int startInputReason,
|
||||
in IInputMethodClient client, in IBinder windowToken,
|
||||
/* @StartInputFlags */ int startInputFlags,
|
||||
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
|
||||
int windowFlags, in EditorInfo attribute, IInputContext inputContext,
|
||||
/* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags,
|
||||
int unverifiedTargetSdkVersion);
|
||||
int unverifiedTargetSdkVersion,
|
||||
in IInputBindResultResultCallback inputBindResult);
|
||||
|
||||
void showInputMethodPickerFromClient(in IInputMethodClient client,
|
||||
int auxiliarySubtypeMode);
|
||||
|
||||
@@ -158,6 +158,8 @@ 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.IInputBindResultResultCallback;
|
||||
import com.android.internal.inputmethod.IInputContentUriToken;
|
||||
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
|
||||
import com.android.internal.inputmethod.InputMethodDebug;
|
||||
@@ -208,6 +210,7 @@ import java.util.Objects;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* This class provides a system service that manages input methods.
|
||||
@@ -3347,63 +3350,68 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public InputBindResult startInputOrWindowGainedFocus(
|
||||
public void startInputOrWindowGainedFocus(
|
||||
@StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
|
||||
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
|
||||
int windowFlags, @Nullable EditorInfo attribute, 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);
|
||||
@MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion,
|
||||
IInputBindResultResultCallback resultCallback) {
|
||||
CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () -> {
|
||||
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;
|
||||
}
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
@@ -72,6 +72,8 @@ import android.view.inputmethod.InputMethodSubtype;
|
||||
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.IInputBindResultResultCallback;
|
||||
import com.android.internal.inputmethod.IMultiClientInputMethod;
|
||||
import com.android.internal.inputmethod.IMultiClientInputMethodPrivilegedOperations;
|
||||
import com.android.internal.inputmethod.IMultiClientInputMethodSession;
|
||||
@@ -104,6 +106,7 @@ import java.lang.annotation.Retention;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Actual implementation of multi-client InputMethodManagerService.
|
||||
@@ -1588,7 +1591,26 @@ public final class MultiClientInputMethodManagerService {
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public InputBindResult startInputOrWindowGainedFocus(
|
||||
public void startInputOrWindowGainedFocus(
|
||||
@StartInputReason int startInputReason,
|
||||
@Nullable IInputMethodClient client,
|
||||
@Nullable IBinder windowToken,
|
||||
@StartInputFlags int startInputFlags,
|
||||
@SoftInputModeFlags int softInputMode,
|
||||
int windowFlags,
|
||||
@Nullable EditorInfo editorInfo,
|
||||
@Nullable IInputContext inputContext,
|
||||
@MissingMethodFlags int missingMethods,
|
||||
int unverifiedTargetSdkVersion,
|
||||
IInputBindResultResultCallback resultCallback) {
|
||||
CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () ->
|
||||
startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
|
||||
startInputFlags, softInputMode, windowFlags, editorInfo, inputContext,
|
||||
missingMethods, unverifiedTargetSdkVersion));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
private InputBindResult startInputOrWindowGainedFocusInternal(
|
||||
@StartInputReason int startInputReason,
|
||||
@Nullable IInputMethodClient client,
|
||||
@Nullable IBinder windowToken,
|
||||
@@ -1676,8 +1698,7 @@ public final class MultiClientInputMethodManagerService {
|
||||
clientInfo.mMSInputMethodSession.startInputOrWindowGainedFocus(
|
||||
inputContext, missingMethods, editorInfo, startInputFlags,
|
||||
softInputMode, windowHandle);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
} catch (RemoteException ignored) { }
|
||||
break;
|
||||
}
|
||||
return InputBindResult.NULL_EDITOR_INFO;
|
||||
@@ -1708,8 +1729,7 @@ public final class MultiClientInputMethodManagerService {
|
||||
clientInfo.mMSInputMethodSession.startInputOrWindowGainedFocus(
|
||||
inputContext, missingMethods, editorInfo, startInputFlags,
|
||||
softInputMode, windowHandle);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
} catch (RemoteException ignored) { }
|
||||
clientInfo.mState = InputMethodClientState.ALREADY_SENT_BIND_RESULT;
|
||||
return new InputBindResult(
|
||||
InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
|
||||
|
||||
Reference in New Issue
Block a user