Loading core/api/current.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -53486,6 +53486,7 @@ package android.view.inputmethod { method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle); method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle); method @Deprecated public void setAdditionalInputMethodSubtypes(@NonNull String, @NonNull android.view.inputmethod.InputMethodSubtype[]); method @Deprecated public void setAdditionalInputMethodSubtypes(@NonNull String, @NonNull android.view.inputmethod.InputMethodSubtype[]); method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype); method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype); method public void setExplicitlyEnabledInputMethodSubtypes(@NonNull String, @NonNull int[]); method @Deprecated public void setInputMethod(android.os.IBinder, String); method @Deprecated public void setInputMethod(android.os.IBinder, String); method @Deprecated public void setInputMethodAndSubtype(@NonNull android.os.IBinder, String, android.view.inputmethod.InputMethodSubtype); method @Deprecated public void setInputMethodAndSubtype(@NonNull android.os.IBinder, String, android.view.inputmethod.InputMethodSubtype); method @Deprecated public boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder); method @Deprecated public boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder); core/java/android/view/inputmethod/IInputMethodManagerInvoker.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -201,6 +201,16 @@ final class IInputMethodManagerInvoker { } } } } @AnyThread void setExplicitlyEnabledInputMethodSubtypes(@NonNull String imeId, @NonNull int[] subtypeHashCodes, @UserIdInt int userId) { try { mTarget.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread @AnyThread int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) { int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) { try { try { Loading core/java/android/view/inputmethod/InputMethodManager.java +50 −0 Original line number Original line Diff line number Diff line Loading @@ -3632,6 +3632,56 @@ public final class InputMethodManager { mServiceInvoker.setAdditionalInputMethodSubtypes(imiId, subtypes, UserHandle.myUserId()); mServiceInvoker.setAdditionalInputMethodSubtypes(imiId, subtypes, UserHandle.myUserId()); } } /** * Updates the list of explicitly enabled {@link InputMethodSubtype} for a given IME owned by * the calling process. * * <p>By default each IME has no explicitly enabled {@link InputMethodSubtype}. In this state * the system will decide what {@link InputMethodSubtype} should be enabled by using information * available at runtime as per-user language settings. Users can, however, manually pick up one * or more {@link InputMethodSubtype} to be enabled on an Activity shown by * {@link #showInputMethodAndSubtypeEnabler(String)}. Such a manual change is stored in * {@link Settings.Secure#ENABLED_INPUT_METHODS} so that the change can persist across reboots. * {@link Settings.Secure#ENABLED_INPUT_METHODS} stores {@link InputMethodSubtype#hashCode()} as * the identifier of {@link InputMethodSubtype} for historical reasons.</p> * * <p>This API provides a safe and managed way for IME developers to modify what * {@link InputMethodSubtype} are referenced in {@link Settings.Secure#ENABLED_INPUT_METHODS} * for their own IME. One use case is when IME developers want to use their own Activity for * users to pick up {@link InputMethodSubtype}. Another use case is for IME developers to fix up * any stale and/or invalid value stored in {@link Settings.Secure#ENABLED_INPUT_METHODS} * without bothering users. Passing an empty {@code subtypeHashCodes} is guaranteed to reset * the state to default.</p> * * <h3>To control the return value of {@link InputMethodSubtype#hashCode()}</h3> * <p>{@link android.R.attr#subtypeId} and {@link * android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder#setSubtypeId(int)} are * available for IME developers to control the return value of * {@link InputMethodSubtype#hashCode()}. Beware that {@code -1} is not a valid value of * {@link InputMethodSubtype#hashCode()} for historical reasons.</p> * * <h3>Note for Direct Boot support</h3> * <p>While IME developers can call this API even before * {@link android.os.UserManager#isUserUnlocked()} becomes {@code true}, such a change is * volatile thus remains effective only until {@link android.os.UserManager#isUserUnlocked()} * becomes {@code true} or the device is rebooted. To make the change persistent IME developers * need to call this API again after receiving {@link Intent#ACTION_USER_UNLOCKED}.</p> * * @param imiId IME ID. The specified IME and the calling process need to belong to the same * package. Otherwise {@link SecurityException} will be thrown. * @param subtypeHashCodes An arrays of {@link InputMethodSubtype#hashCode()} to be explicitly * enabled. Entries that are found in the specified IME will be silently * ignored. Pass an empty array to reset the state to default. * @throws NullPointerException if {@code subtypeHashCodes} is {@code null}. * @throws SecurityException if the specified IME and the calling process do not belong to the * same package. */ public void setExplicitlyEnabledInputMethodSubtypes(@NonNull String imiId, @NonNull int[] subtypeHashCodes) { mServiceInvoker.setExplicitlyEnabledInputMethodSubtypes(imiId, subtypeHashCodes, UserHandle.myUserId()); } /** /** * Returns the last used {@link InputMethodSubtype} in system history. * Returns the last used {@link InputMethodSubtype} in system history. * * Loading core/java/com/android/internal/view/IInputMethodManager.aidl +5 −0 Original line number Original line Diff line number Diff line Loading @@ -97,6 +97,11 @@ interface IInputMethodManager { void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes, void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes, int userId); int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)") void setExplicitlyEnabledInputMethodSubtypes(String imeId, in int[] subtypeHashCodes, int userId); // This is kept due to @UnsupportedAppUsage. // This is kept due to @UnsupportedAppUsage. // TODO(Bug 113914148): Consider removing this. // TODO(Bug 113914148): Consider removing this. int getInputMethodWindowVisibleHeight(in IInputMethodClient client); int getInputMethodWindowVisibleHeight(in IInputMethodClient client); Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +41 −0 Original line number Original line Diff line number Diff line Loading @@ -75,6 +75,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentResolver; import android.content.Context; import android.content.Context; Loading Loading @@ -4214,6 +4215,46 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } } } @Override public void setExplicitlyEnabledInputMethodSubtypes(String imeId, @NonNull int[] subtypeHashCodes, @UserIdInt int userId) { if (UserHandle.getCallingUserId() != userId) { mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); } final int callingUid = Binder.getCallingUid(); final ComponentName imeComponentName = imeId != null ? ComponentName.unflattenFromString(imeId) : null; if (imeComponentName == null || !InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, callingUid, imeComponentName.getPackageName())) { throw new SecurityException("Calling UID=" + callingUid + " does not belong to imeId=" + imeId); } Objects.requireNonNull(subtypeHashCodes, "subtypeHashCodes must not be null"); final long ident = Binder.clearCallingIdentity(); try { synchronized (ImfLock.class) { final boolean currentUser = (mSettings.getCurrentUserId() == userId); final InputMethodSettings settings = currentUser ? mSettings : new InputMethodSettings(mContext, queryMethodMapForUser(userId), userId, !mUserManagerInternal.isUserUnlocked(userId)); if (!settings.setEnabledInputMethodSubtypes(imeId, subtypeHashCodes)) { return; } if (currentUser) { // To avoid unnecessary "updateInputMethodsFromSettingsLocked" from happening. if (mSettingsObserver != null) { mSettingsObserver.mLastEnabled = settings.getEnabledInputMethodsStr(); } updateInputMethodsFromSettingsLocked(false /* enabledChanged */); } } } finally { Binder.restoreCallingIdentity(ident); } } /** /** * This is kept due to {@code @UnsupportedAppUsage} in * This is kept due to {@code @UnsupportedAppUsage} in * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in Loading Loading
core/api/current.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -53486,6 +53486,7 @@ package android.view.inputmethod { method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle); method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle); method @Deprecated public void setAdditionalInputMethodSubtypes(@NonNull String, @NonNull android.view.inputmethod.InputMethodSubtype[]); method @Deprecated public void setAdditionalInputMethodSubtypes(@NonNull String, @NonNull android.view.inputmethod.InputMethodSubtype[]); method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype); method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype); method public void setExplicitlyEnabledInputMethodSubtypes(@NonNull String, @NonNull int[]); method @Deprecated public void setInputMethod(android.os.IBinder, String); method @Deprecated public void setInputMethod(android.os.IBinder, String); method @Deprecated public void setInputMethodAndSubtype(@NonNull android.os.IBinder, String, android.view.inputmethod.InputMethodSubtype); method @Deprecated public void setInputMethodAndSubtype(@NonNull android.os.IBinder, String, android.view.inputmethod.InputMethodSubtype); method @Deprecated public boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder); method @Deprecated public boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder);
core/java/android/view/inputmethod/IInputMethodManagerInvoker.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -201,6 +201,16 @@ final class IInputMethodManagerInvoker { } } } } @AnyThread void setExplicitlyEnabledInputMethodSubtypes(@NonNull String imeId, @NonNull int[] subtypeHashCodes, @UserIdInt int userId) { try { mTarget.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread @AnyThread int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) { int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) { try { try { Loading
core/java/android/view/inputmethod/InputMethodManager.java +50 −0 Original line number Original line Diff line number Diff line Loading @@ -3632,6 +3632,56 @@ public final class InputMethodManager { mServiceInvoker.setAdditionalInputMethodSubtypes(imiId, subtypes, UserHandle.myUserId()); mServiceInvoker.setAdditionalInputMethodSubtypes(imiId, subtypes, UserHandle.myUserId()); } } /** * Updates the list of explicitly enabled {@link InputMethodSubtype} for a given IME owned by * the calling process. * * <p>By default each IME has no explicitly enabled {@link InputMethodSubtype}. In this state * the system will decide what {@link InputMethodSubtype} should be enabled by using information * available at runtime as per-user language settings. Users can, however, manually pick up one * or more {@link InputMethodSubtype} to be enabled on an Activity shown by * {@link #showInputMethodAndSubtypeEnabler(String)}. Such a manual change is stored in * {@link Settings.Secure#ENABLED_INPUT_METHODS} so that the change can persist across reboots. * {@link Settings.Secure#ENABLED_INPUT_METHODS} stores {@link InputMethodSubtype#hashCode()} as * the identifier of {@link InputMethodSubtype} for historical reasons.</p> * * <p>This API provides a safe and managed way for IME developers to modify what * {@link InputMethodSubtype} are referenced in {@link Settings.Secure#ENABLED_INPUT_METHODS} * for their own IME. One use case is when IME developers want to use their own Activity for * users to pick up {@link InputMethodSubtype}. Another use case is for IME developers to fix up * any stale and/or invalid value stored in {@link Settings.Secure#ENABLED_INPUT_METHODS} * without bothering users. Passing an empty {@code subtypeHashCodes} is guaranteed to reset * the state to default.</p> * * <h3>To control the return value of {@link InputMethodSubtype#hashCode()}</h3> * <p>{@link android.R.attr#subtypeId} and {@link * android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder#setSubtypeId(int)} are * available for IME developers to control the return value of * {@link InputMethodSubtype#hashCode()}. Beware that {@code -1} is not a valid value of * {@link InputMethodSubtype#hashCode()} for historical reasons.</p> * * <h3>Note for Direct Boot support</h3> * <p>While IME developers can call this API even before * {@link android.os.UserManager#isUserUnlocked()} becomes {@code true}, such a change is * volatile thus remains effective only until {@link android.os.UserManager#isUserUnlocked()} * becomes {@code true} or the device is rebooted. To make the change persistent IME developers * need to call this API again after receiving {@link Intent#ACTION_USER_UNLOCKED}.</p> * * @param imiId IME ID. The specified IME and the calling process need to belong to the same * package. Otherwise {@link SecurityException} will be thrown. * @param subtypeHashCodes An arrays of {@link InputMethodSubtype#hashCode()} to be explicitly * enabled. Entries that are found in the specified IME will be silently * ignored. Pass an empty array to reset the state to default. * @throws NullPointerException if {@code subtypeHashCodes} is {@code null}. * @throws SecurityException if the specified IME and the calling process do not belong to the * same package. */ public void setExplicitlyEnabledInputMethodSubtypes(@NonNull String imiId, @NonNull int[] subtypeHashCodes) { mServiceInvoker.setExplicitlyEnabledInputMethodSubtypes(imiId, subtypeHashCodes, UserHandle.myUserId()); } /** /** * Returns the last used {@link InputMethodSubtype} in system history. * Returns the last used {@link InputMethodSubtype} in system history. * * Loading
core/java/com/android/internal/view/IInputMethodManager.aidl +5 −0 Original line number Original line Diff line number Diff line Loading @@ -97,6 +97,11 @@ interface IInputMethodManager { void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes, void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes, int userId); int userId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)") void setExplicitlyEnabledInputMethodSubtypes(String imeId, in int[] subtypeHashCodes, int userId); // This is kept due to @UnsupportedAppUsage. // This is kept due to @UnsupportedAppUsage. // TODO(Bug 113914148): Consider removing this. // TODO(Bug 113914148): Consider removing this. int getInputMethodWindowVisibleHeight(in IInputMethodClient client); int getInputMethodWindowVisibleHeight(in IInputMethodClient client); Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +41 −0 Original line number Original line Diff line number Diff line Loading @@ -75,6 +75,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentResolver; import android.content.Context; import android.content.Context; Loading Loading @@ -4214,6 +4215,46 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } } } @Override public void setExplicitlyEnabledInputMethodSubtypes(String imeId, @NonNull int[] subtypeHashCodes, @UserIdInt int userId) { if (UserHandle.getCallingUserId() != userId) { mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); } final int callingUid = Binder.getCallingUid(); final ComponentName imeComponentName = imeId != null ? ComponentName.unflattenFromString(imeId) : null; if (imeComponentName == null || !InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, callingUid, imeComponentName.getPackageName())) { throw new SecurityException("Calling UID=" + callingUid + " does not belong to imeId=" + imeId); } Objects.requireNonNull(subtypeHashCodes, "subtypeHashCodes must not be null"); final long ident = Binder.clearCallingIdentity(); try { synchronized (ImfLock.class) { final boolean currentUser = (mSettings.getCurrentUserId() == userId); final InputMethodSettings settings = currentUser ? mSettings : new InputMethodSettings(mContext, queryMethodMapForUser(userId), userId, !mUserManagerInternal.isUserUnlocked(userId)); if (!settings.setEnabledInputMethodSubtypes(imeId, subtypeHashCodes)) { return; } if (currentUser) { // To avoid unnecessary "updateInputMethodsFromSettingsLocked" from happening. if (mSettingsObserver != null) { mSettingsObserver.mLastEnabled = settings.getEnabledInputMethodsStr(); } updateInputMethodsFromSettingsLocked(false /* enabledChanged */); } } } finally { Binder.restoreCallingIdentity(ident); } } /** /** * This is kept due to {@code @UnsupportedAppUsage} in * This is kept due to {@code @UnsupportedAppUsage} in * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in Loading