Add InputMethodManagerDelegate#getLockObject

As CL[1] introduces per-window based ImeFocusController for handling
the IME served view focus update logic.

However, for InputMethodManager APIs requires to access
ImeFocusController#{mServedView, mNextServedView} for starting the input
connection or checking the caller's validity, which needs a lock for
thread safety.

As a result, it would make sense to expose mH for ImeFocusController
through an new method InputMethodManagerDelegate#getLockObject
to protect the data consistancy during InputMethodMananger APIs
invoking to access the served view.

Also, renaming the methods (and update the javadoc) with "Locked" sufix:
- ImeFocusController#get{Served, NextServed}View
- ImeFocusController#set{Served, NextServed}View

Note that this is a refactoring preperation CL with added a TODO that
will use getLockObject in the follow-up CL.

[1]: Ib455704fe1e9d243f93190a84f230210dbceac2a

Bug: 244504062
Test: atest CtsInputMethodTestCases
Change-Id: I9c072b829d1db1e68b65e766d764ee71cb16e6a2
This commit is contained in:
Ming-Shin Lu
2022-09-03 00:00:39 +08:00
parent 4a8abca2d8
commit 31e4678463
3 changed files with 72 additions and 13 deletions

View File

@@ -43,8 +43,21 @@ public final class ImeFocusController {
private final ViewRootImpl mViewRootImpl;
private boolean mHasImeFocus = false;
/**
* This is the view that should currently be served by an input method,
* regardless of the state of setting that up.
* @see InputMethodManagerDelegate#getLockObject()
*/
private View mServedView;
/**
* This is the next view that will be served by the input method, when
* we get around to updating things.
* @see InputMethodManagerDelegate#getLockObject()
*/
private View mNextServedView;
private InputMethodManagerDelegate mDelegate;
@UiThread
@@ -284,21 +297,44 @@ public final class ImeFocusController {
boolean isCurrentRootView(ViewRootImpl rootView);
boolean isRestartOnNextWindowFocus(boolean reset);
boolean hasActiveConnection(View view);
/**
* Returns the {@code InputMethodManager#mH} lock object.
* Used for {@link ImeFocusController} to guard the served view being accessed by
* {@link InputMethodManager} in different threads.
*
* TODO(b/244504062): Use this to all places requires synchronization in controller.
*/
Object getLockObject();
}
public View getServedView() {
/**
* Returns The current IME served view for {@link InputMethodManager}.
* Used to start input connection or check the caller's validity when calling
* {@link InputMethodManager} APIs.
* Note that this method requires to be called inside {@code InputMethodManager#mH} lock for
* data consistency.
*/
public View getServedViewLocked() {
return mServedView;
}
public View getNextServedView() {
/**
* Returns The next incoming IME served view for {@link InputMethodManager}.
* Note that this method requires to be called inside {@code InputMethodManager#mH} lock for
* data consistency.
*/
public View getNextServedViewLocked() {
return mNextServedView;
}
public void setServedView(View view) {
// TODO(b/244504062): Remove this method dependency from InputMethodManager.
public void setServedViewLocked(View view) {
mServedView = view;
}
public void setNextServedView(View view) {
// TODO(b/244504062): Remove this method dependency from InputMethodManager.
public void setNextServedViewLocked(View view) {
mNextServedView = view;
}

View File

@@ -838,11 +838,8 @@ public class BaseInputConnection implements InputConnection {
Context context;
if (mTargetView != null) {
context = mTargetView.getContext();
} else if (mIMM.mCurRootView != null) {
final View servedView = mIMM.mCurRootView.getImeFocusController().getServedView();
context = servedView != null ? servedView.getContext() : null;
} else {
context = null;
context = mIMM.getFallbackContextFromServedView();
}
if (context != null) {
TypedArray ta = context.getTheme()

View File

@@ -677,6 +677,21 @@ public final class InputMethodManager {
return fallbackImm;
}
/**
* An internal API that returns the {@link Context} of the current served view connected to
* an input method.
* @hide
*/
Context getFallbackContextFromServedView() {
synchronized (mH) {
if (mCurRootView == null) {
return null;
}
final View servedView = mCurRootView.getImeFocusController().getServedViewLocked();
return servedView != null ? servedView.getContext() : null;
}
}
private static boolean canStartInput(View servedView) {
// We can start input ether the servedView has window focus
// or the activity is showing autofill ui.
@@ -786,7 +801,7 @@ public final class InputMethodManager {
synchronized (mH) {
// For some reason we didn't do a startInput + windowFocusGain, so
// we'll just do a window focus gain and call it a day.
View servedView = controller.getServedView();
View servedView = controller.getServedViewLocked();
boolean nextFocusHasConnection = servedView != null && servedView == focusedView
&& hasActiveConnection(focusedView);
if (DEBUG) {
@@ -878,6 +893,16 @@ public final class InputMethodManager {
&& mServedInputConnection.getServedView() == view;
}
}
/**
* Returns the {@link InputMethodManager#mH} lock object.
* Used for {@link ImeFocusController} to guard the served view being accessed by
* {@link InputMethodManager} in different threads.
*/
@Override
public Object getLockObject() {
return mH;
}
}
/** @hide */
@@ -898,26 +923,27 @@ public final class InputMethodManager {
@GuardedBy("mH")
private View getServedViewLocked() {
return mCurRootView != null ? mCurRootView.getImeFocusController().getServedView() : null;
return mCurRootView != null ? mCurRootView.getImeFocusController().getServedViewLocked()
: null;
}
@GuardedBy("mH")
private View getNextServedViewLocked() {
return mCurRootView != null ? mCurRootView.getImeFocusController().getNextServedView()
return mCurRootView != null ? mCurRootView.getImeFocusController().getNextServedViewLocked()
: null;
}
@GuardedBy("mH")
private void setServedViewLocked(View view) {
if (mCurRootView != null) {
mCurRootView.getImeFocusController().setServedView(view);
mCurRootView.getImeFocusController().setServedViewLocked(view);
}
}
@GuardedBy("mH")
private void setNextServedViewLocked(View view) {
if (mCurRootView != null) {
mCurRootView.getImeFocusController().setNextServedView(view);
mCurRootView.getImeFocusController().setNextServedViewLocked(view);
}
}