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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user