diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index 9c421524d723d..9f76e1ed113df 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -33,6 +33,16 @@ import java.util.List; * Input method manager local system service interface. */ public abstract class InputMethodManagerInternal { + /** + * Listener for input method list changed events. + */ + public interface InputMethodListListener { + /** + * Called with the list of the installed IMEs when it's updated. + */ + void onInputMethodListUpdated(List info, @UserIdInt int userId); + } + /** * Called by the power manager to tell the input method manager whether it * should start watching for wake events. @@ -84,6 +94,11 @@ public abstract class InputMethodManagerInternal { */ public abstract boolean switchToInputMethod(String imeId, @UserIdInt int userId); + /** + * Registers a new {@link InputMethodListListener}. + */ + public abstract void registerInputMethodListListener(InputMethodListListener listener); + /** * Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing. */ @@ -117,6 +132,10 @@ public abstract class InputMethodManagerInternal { public boolean switchToInputMethod(String imeId, int userId) { return false; } + + @Override + public void registerInputMethodListListener(InputMethodListListener listener) { + } }; /** diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 15698e9795ec6..47622f38f3f22 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -154,6 +154,7 @@ import com.android.internal.view.InputBindResult; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener; import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings; import com.android.server.statusbar.StatusBarManagerService; @@ -172,6 +173,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; import java.util.WeakHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; /** @@ -214,6 +216,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000; static final int MSG_SYSTEM_UNLOCK_USER = 5000; + static final int MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED = 5010; static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000; @@ -688,6 +691,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final IPackageManager mIPackageManager; private final String mSlotIme; + /** + * Registered {@link InputMethodListListeners}. + * This variable can be accessed from both of MainThread and BinderThread. + */ + private final CopyOnWriteArrayList mInputMethodListListeners = + new CopyOnWriteArrayList<>(); + /** * Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the * internal message queue. Any subsequent state change inside {@link InputMethodManagerService} @@ -3946,10 +3956,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub case MSG_HARD_KEYBOARD_SWITCH_CHANGED: mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1); return true; - case MSG_SYSTEM_UNLOCK_USER: + case MSG_SYSTEM_UNLOCK_USER: { final int userId = msg.arg1; onUnlockUser(userId); return true; + } + case MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED: { + final int userId = msg.arg1; + final List imes = (List) msg.obj; + mInputMethodListListeners.forEach( + listener -> listener.onInputMethodListUpdated(imes, userId)); + return true; + } // --------------------------------------------------------------- case MSG_INLINE_SUGGESTIONS_REQUEST: @@ -4142,6 +4160,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // TODO: Make sure that mSwitchingController and mSettings are sharing the // the same enabled IMEs list. mSwitchingController.resetCircularListLocked(mContext); + + // Notify InputMethodListListeners of the new installed InputMethods. + final List inputMethodList = new ArrayList<>(mMethodList); + mHandler.obtainMessage(MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED, + mSettings.getCurrentUserId(), 0 /* unused */, inputMethodList).sendToTarget(); } // ---------------------------------------------------------------------- @@ -4606,6 +4629,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub public boolean switchToInputMethod(String imeId, int userId) { return mService.switchToInputMethod(imeId, userId); } + + @Override + public void registerInputMethodListListener(InputMethodListListener listener) { + mService.mInputMethodListListeners.addIfAbsent(listener); + } } @BinderThread diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index d09c478e320f3..54af69432ee0e 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -207,6 +207,12 @@ public final class MultiClientInputMethodManagerService { reportNotSupported(); return false; } + + @Override + public void registerInputMethodListListener( + InputMethodListListener listener) { + reportNotSupported(); + } }); }