Merge "Avoid IME restart for configChanges" into sc-dev
This commit is contained in:
@@ -51476,6 +51476,7 @@ package android.view.inputmethod {
|
|||||||
method public int describeContents();
|
method public int describeContents();
|
||||||
method public void dump(android.util.Printer, String);
|
method public void dump(android.util.Printer, String);
|
||||||
method public android.content.ComponentName getComponent();
|
method public android.content.ComponentName getComponent();
|
||||||
|
method public int getConfigChanges();
|
||||||
method public String getId();
|
method public String getId();
|
||||||
method public int getIsDefaultResourceId();
|
method public int getIsDefaultResourceId();
|
||||||
method public String getPackageName();
|
method public String getPackageName();
|
||||||
|
|||||||
@@ -2699,6 +2699,10 @@ package android.view.inputmethod {
|
|||||||
method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
|
method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class InputMethodInfo implements android.os.Parcelable {
|
||||||
|
ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
|
||||||
|
}
|
||||||
|
|
||||||
public final class InputMethodManager {
|
public final class InputMethodManager {
|
||||||
method public int getDisplayId();
|
method public int getDisplayId();
|
||||||
method public boolean hasActiveInputConnection(@Nullable android.view.View);
|
method public boolean hasActiveInputConnection(@Nullable android.view.View);
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
|||||||
SomeArgs args = (SomeArgs) msg.obj;
|
SomeArgs args = (SomeArgs) msg.obj;
|
||||||
try {
|
try {
|
||||||
inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
|
inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
|
||||||
(IInputMethodPrivilegedOperations) args.arg2);
|
(IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3);
|
||||||
} finally {
|
} finally {
|
||||||
args.recycle();
|
args.recycle();
|
||||||
}
|
}
|
||||||
@@ -280,9 +280,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
|||||||
@BinderThread
|
@BinderThread
|
||||||
@Override
|
@Override
|
||||||
public void initializeInternal(IBinder token, int displayId,
|
public void initializeInternal(IBinder token, int displayId,
|
||||||
IInputMethodPrivilegedOperations privOps) {
|
IInputMethodPrivilegedOperations privOps, int configChanges) {
|
||||||
mCaller.executeOrSendMessage(
|
mCaller.executeOrSendMessage(
|
||||||
mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
|
mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps,
|
||||||
|
configChanges));
|
||||||
}
|
}
|
||||||
|
|
||||||
@BinderThread
|
@BinderThread
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import android.compat.annotation.ChangeId;
|
|||||||
import android.compat.annotation.EnabledSince;
|
import android.compat.annotation.EnabledSince;
|
||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -131,6 +132,7 @@ import android.widget.TextView;
|
|||||||
import android.window.WindowMetricsHelper;
|
import android.window.WindowMetricsHelper;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.inputmethod.IInputContentUriToken;
|
import com.android.internal.inputmethod.IInputContentUriToken;
|
||||||
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
|
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
|
||||||
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
|
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
|
||||||
@@ -513,6 +515,8 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
private boolean mIsAutomotive;
|
private boolean mIsAutomotive;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private boolean mImeSurfaceScheduledForRemoval;
|
private boolean mImeSurfaceScheduledForRemoval;
|
||||||
|
private Configuration mLastKnownConfig;
|
||||||
|
private int mHandledConfigChanges;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
|
* An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
|
||||||
@@ -588,12 +592,13 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
@MainThread
|
@MainThread
|
||||||
@Override
|
@Override
|
||||||
public final void initializeInternal(@NonNull IBinder token, int displayId,
|
public final void initializeInternal(@NonNull IBinder token, int displayId,
|
||||||
IInputMethodPrivilegedOperations privilegedOperations) {
|
IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
|
||||||
if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) {
|
if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) {
|
||||||
Log.w(TAG, "The token has already registered, ignore this initialization.");
|
Log.w(TAG, "The token has already registered, ignore this initialization.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
|
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
|
||||||
|
mHandledConfigChanges = configChanges;
|
||||||
mPrivOps.set(privilegedOperations);
|
mPrivOps.set(privilegedOperations);
|
||||||
InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
|
InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
|
||||||
updateInputMethodDisplay(displayId);
|
updateInputMethodDisplay(displayId);
|
||||||
@@ -821,6 +826,9 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
|
setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
|
||||||
}
|
}
|
||||||
final boolean isVisible = isInputViewShown();
|
final boolean isVisible = isInputViewShown();
|
||||||
|
if (isVisible && getResources() != null) {
|
||||||
|
mLastKnownConfig = new Configuration(getResources().getConfiguration());
|
||||||
|
}
|
||||||
final boolean visibilityChanged = isVisible != wasVisible;
|
final boolean visibilityChanged = isVisible != wasVisible;
|
||||||
if (resultReceiver != null) {
|
if (resultReceiver != null) {
|
||||||
resultReceiver.send(visibilityChanged
|
resultReceiver.send(visibilityChanged
|
||||||
@@ -1428,10 +1436,30 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
* state: {@link #onStartInput} if input is active, and
|
* state: {@link #onStartInput} if input is active, and
|
||||||
* {@link #onCreateInputView} and {@link #onStartInputView} and related
|
* {@link #onCreateInputView} and {@link #onStartInputView} and related
|
||||||
* appropriate functions if the UI is displayed.
|
* appropriate functions if the UI is displayed.
|
||||||
|
* <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration
|
||||||
|
* changes themselves instead of being restarted with
|
||||||
|
* {@link android.R.styleable#InputMethod_configChanges}.
|
||||||
*/
|
*/
|
||||||
@Override public void onConfigurationChanged(Configuration newConfig) {
|
@Override public void onConfigurationChanged(Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
resetStateForNewConfiguration();
|
if (shouldImeRestartForConfig(newConfig)) {
|
||||||
|
resetStateForNewConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if {@link InputMethodService} needs to restart to handle
|
||||||
|
* .{@link #onConfigurationChanged(Configuration)}
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) {
|
||||||
|
if (mLastKnownConfig == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If the new config is the same as the config this Service is already running with,
|
||||||
|
// then don't bother calling resetStateForNewConfiguration.
|
||||||
|
int unhandledDiff = (mLastKnownConfig.diffPublicOnly(newConfig) & ~mHandledConfigChanges);
|
||||||
|
return unhandledDiff != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetStateForNewConfiguration() {
|
private void resetStateForNewConfiguration() {
|
||||||
@@ -3182,6 +3210,16 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void setLastKnownConfig(@NonNull Configuration config) {
|
||||||
|
mLastKnownConfig = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void setHandledConfigChanges(int configChanges) {
|
||||||
|
mHandledConfigChanges = configChanges;
|
||||||
|
}
|
||||||
|
|
||||||
void startExtractingText(boolean inputChanged) {
|
void startExtractingText(boolean inputChanged) {
|
||||||
final ExtractEditText eet = mExtractEditText;
|
final ExtractEditText eet = mExtractEditText;
|
||||||
if (eet != null && getCurrentInputStarted()
|
if (eet != null && getCurrentInputStarted()
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public interface InputMethod {
|
|||||||
*/
|
*/
|
||||||
@MainThread
|
@MainThread
|
||||||
default void initializeInternal(IBinder token, int displayId,
|
default void initializeInternal(IBinder token, int displayId,
|
||||||
IInputMethodPrivilegedOperations privilegedOperations) {
|
IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
|
||||||
updateInputMethodDisplay(displayId);
|
updateInputMethodDisplay(displayId);
|
||||||
attachToken(token);
|
attachToken(token);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,23 @@ package android.view.inputmethod;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.annotation.TestApi;
|
||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.Resources.NotFoundException;
|
import android.content.res.Resources.NotFoundException;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.content.res.XmlResourceParser;
|
import android.content.res.XmlResourceParser;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.inputmethodservice.InputMethodService;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -60,6 +64,7 @@ import java.util.List;
|
|||||||
* @attr ref android.R.styleable#InputMethod_isDefault
|
* @attr ref android.R.styleable#InputMethod_isDefault
|
||||||
* @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
|
* @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
|
||||||
* @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
|
* @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
|
||||||
|
* @attr ref android.R.styleable#InputMethod_configChanges
|
||||||
*/
|
*/
|
||||||
public final class InputMethodInfo implements Parcelable {
|
public final class InputMethodInfo implements Parcelable {
|
||||||
static final String TAG = "InputMethodInfo";
|
static final String TAG = "InputMethodInfo";
|
||||||
@@ -117,6 +122,12 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
private final boolean mInlineSuggestionsEnabled;
|
private final boolean mInlineSuggestionsEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flag for configurations IME assumes the responsibility for handling in
|
||||||
|
* {@link InputMethodService#onConfigurationChanged(Configuration)}}.
|
||||||
|
*/
|
||||||
|
private final int mHandledConfigChanges;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
|
* @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
|
||||||
* @return a unique ID to be returned by {@link #getId()}. We have used
|
* @return a unique ID to be returned by {@link #getId()}. We have used
|
||||||
@@ -203,6 +214,8 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
false);
|
false);
|
||||||
inlineSuggestionsEnabled = sa.getBoolean(
|
inlineSuggestionsEnabled = sa.getBoolean(
|
||||||
com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
|
com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
|
||||||
|
mHandledConfigChanges = sa.getInt(
|
||||||
|
com.android.internal.R.styleable.InputMethod_configChanges, 0);
|
||||||
sa.recycle();
|
sa.recycle();
|
||||||
|
|
||||||
final int depth = parser.getDepth();
|
final int depth = parser.getDepth();
|
||||||
@@ -287,6 +300,7 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
mIsVrOnly = source.readBoolean();
|
mIsVrOnly = source.readBoolean();
|
||||||
mService = ResolveInfo.CREATOR.createFromParcel(source);
|
mService = ResolveInfo.CREATOR.createFromParcel(source);
|
||||||
mSubtypes = new InputMethodSubtypeArray(source);
|
mSubtypes = new InputMethodSubtypeArray(source);
|
||||||
|
mHandledConfigChanges = source.readInt();
|
||||||
mForceDefault = false;
|
mForceDefault = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +312,22 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
|
this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
|
||||||
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
|
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
|
||||||
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
|
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
|
||||||
false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
|
false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
|
||||||
|
0 /* handledConfigChanges */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary API for creating a built-in input method for test.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@TestApi
|
||||||
|
public InputMethodInfo(@NonNull String packageName, @NonNull String className,
|
||||||
|
@NonNull CharSequence label, @NonNull String settingsActivity,
|
||||||
|
int handledConfigChanges) {
|
||||||
|
this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
|
||||||
|
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
|
||||||
|
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
|
||||||
|
false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,7 +339,7 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
boolean forceDefault) {
|
boolean forceDefault) {
|
||||||
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
|
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
|
||||||
true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
|
true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
|
||||||
false /* isVrOnly */);
|
false /* isVrOnly */, 0 /* handledconfigChanges */);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,7 +350,8 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
|
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
|
||||||
boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
|
boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
|
||||||
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
|
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
|
||||||
supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly);
|
supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
|
||||||
|
0 /* handledConfigChanges */);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -331,7 +361,7 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
|
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
|
||||||
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
|
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
|
||||||
boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
|
boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
|
||||||
boolean isVrOnly) {
|
boolean isVrOnly, int handledConfigChanges) {
|
||||||
final ServiceInfo si = ri.serviceInfo;
|
final ServiceInfo si = ri.serviceInfo;
|
||||||
mService = ri;
|
mService = ri;
|
||||||
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
|
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
|
||||||
@@ -343,6 +373,7 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
|
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
|
||||||
mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
|
mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
|
||||||
mIsVrOnly = isVrOnly;
|
mIsVrOnly = isVrOnly;
|
||||||
|
mHandledConfigChanges = handledConfigChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
|
private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
|
||||||
@@ -489,6 +520,17 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the bit mask of kinds of configuration changes that this IME
|
||||||
|
* can handle itself (without being restarted by the system).
|
||||||
|
*
|
||||||
|
* @attr ref android.R.styleable#InputMethod_configChanges
|
||||||
|
*/
|
||||||
|
@ActivityInfo.Config
|
||||||
|
public int getConfigChanges() {
|
||||||
|
return mHandledConfigChanges;
|
||||||
|
}
|
||||||
|
|
||||||
public void dump(Printer pw, String prefix) {
|
public void dump(Printer pw, String prefix) {
|
||||||
pw.println(prefix + "mId=" + mId
|
pw.println(prefix + "mId=" + mId
|
||||||
+ " mSettingsActivityName=" + mSettingsActivityName
|
+ " mSettingsActivityName=" + mSettingsActivityName
|
||||||
@@ -579,6 +621,7 @@ public final class InputMethodInfo implements Parcelable {
|
|||||||
dest.writeBoolean(mIsVrOnly);
|
dest.writeBoolean(mIsVrOnly);
|
||||||
mService.writeToParcel(dest, flags);
|
mService.writeToParcel(dest, flags);
|
||||||
mSubtypes.writeToParcel(dest);
|
mSubtypes.writeToParcel(dest);
|
||||||
|
dest.writeInt(mHandledConfigChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ import com.android.internal.view.InlineSuggestionsRequestInfo;
|
|||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
oneway interface IInputMethod {
|
oneway interface IInputMethod {
|
||||||
void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
|
void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps,
|
||||||
|
int configChanges);
|
||||||
|
|
||||||
void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
|
void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
|
||||||
in IInlineSuggestionsRequestCallback cb);
|
in IInlineSuggestionsRequestCallback cb);
|
||||||
|
|||||||
@@ -3564,6 +3564,16 @@
|
|||||||
<attr name="__removed2" format="boolean" />
|
<attr name="__removed2" format="boolean" />
|
||||||
<!-- Specifies whether the IME supports showing inline suggestions. -->
|
<!-- Specifies whether the IME supports showing inline suggestions. -->
|
||||||
<attr name="supportsInlineSuggestions" format="boolean" />
|
<attr name="supportsInlineSuggestions" format="boolean" />
|
||||||
|
<!-- Specify one or more configuration changes that the IME will handle itself. If not
|
||||||
|
specified, the IME will be restarted if any of these configuration changes happen in
|
||||||
|
the system. Otherwise, the IME will remain running and its
|
||||||
|
{@link android.inputmethodservice.InputMethodService#onConfigurationChanged}
|
||||||
|
method is called with the new configuration.
|
||||||
|
<p>Note that all of these configuration changes can impact the
|
||||||
|
resource values seen by the application, so you will generally need
|
||||||
|
to re-retrieve all resources (including view layouts, drawables, etc)
|
||||||
|
to correctly handle any configuration change.-->
|
||||||
|
<attr name="configChanges" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
|
<!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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 android.inputmethodservice;
|
||||||
|
|
||||||
|
import static android.content.res.Configuration.KEYBOARD_12KEY;
|
||||||
|
import static android.content.res.Configuration.NAVIGATION_NONAV;
|
||||||
|
|
||||||
|
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||||
|
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class InputMethodServiceTest {
|
||||||
|
private InputMethodService mService;
|
||||||
|
private Context mContext;
|
||||||
|
@Rule
|
||||||
|
public final ServiceTestRule serviceRule = new ServiceTestRule();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws TimeoutException {
|
||||||
|
mContext = getInstrumentation().getContext();
|
||||||
|
mService = new InputMethodService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldImeRestartForConfig() throws Exception {
|
||||||
|
// Make sure we preserve Pre-S behavior i.e. Service restarts.
|
||||||
|
mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R;
|
||||||
|
Configuration config = mContext.getResources().getConfiguration();
|
||||||
|
mService.setLastKnownConfig(config);
|
||||||
|
assertTrue("IME should restart for Pre-S",
|
||||||
|
mService.shouldImeRestartForConfig(config));
|
||||||
|
|
||||||
|
// IME shouldn't restart on targetSdk S+ (with no config changes).
|
||||||
|
mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S;
|
||||||
|
assertFalse("IME shouldn't restart for S+",
|
||||||
|
mService.shouldImeRestartForConfig(config));
|
||||||
|
|
||||||
|
// Screen density changed but IME doesn't handle congfigChanges
|
||||||
|
config.densityDpi = 99;
|
||||||
|
assertTrue("IME should restart for unhandled configChanges",
|
||||||
|
mService.shouldImeRestartForConfig(config));
|
||||||
|
|
||||||
|
// opt-in IME to handle config changes.
|
||||||
|
mService.setHandledConfigChanges(ActivityInfo.CONFIG_DENSITY);
|
||||||
|
assertFalse("IME shouldn't restart for S+ since it handles configChanges",
|
||||||
|
mService.shouldImeRestartForConfig(config));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2621,8 +2621,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
}
|
}
|
||||||
if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
|
if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
|
||||||
// Dispatch display id for InputMethodService to update context display.
|
// Dispatch display id for InputMethodService to update context display.
|
||||||
executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
|
executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(
|
||||||
MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
|
MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken,
|
||||||
|
mMethodMap.get(mCurMethodId).getConfigChanges()));
|
||||||
scheduleNotifyImeUidToAudioService(mCurMethodUid);
|
scheduleNotifyImeUidToAudioService(mCurMethodUid);
|
||||||
if (mCurClient != null) {
|
if (mCurClient != null) {
|
||||||
clearClientSessionLocked(mCurClient);
|
clearClientSessionLocked(mCurClient);
|
||||||
@@ -4478,7 +4479,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
}
|
}
|
||||||
final IBinder token = (IBinder) args.arg2;
|
final IBinder token = (IBinder) args.arg2;
|
||||||
((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
|
((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
|
||||||
new InputMethodPrivilegedOperationsImpl(this, token));
|
new InputMethodPrivilegedOperationsImpl(this, token),
|
||||||
|
(int) args.arg3);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
}
|
}
|
||||||
args.recycle();
|
args.recycle();
|
||||||
|
|||||||
Reference in New Issue
Block a user