Loading core/java/android/view/ImeFocusController.java 0 → 100644 +234 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.view; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.UiThread; import android.util.Log; import android.view.inputmethod.InputMethodManager; import com.android.internal.inputmethod.InputMethodDebug; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; /** * Responsible for IME focus handling inside {@link ViewRootImpl}. * @hide */ public final class ImeFocusController { private static final boolean DEBUG = false; private static final String TAG = "ImeFocusController"; private final ViewRootImpl mViewRootImpl; private boolean mHasImeFocus = false; private View mServedView; private View mNextServedView; @UiThread ImeFocusController(@NonNull ViewRootImpl viewRootImpl) { mViewRootImpl = viewRootImpl; } private InputMethodManagerDelegate getImmDelegate() { return mViewRootImpl.mContext.getSystemService(InputMethodManager.class).getDelegate(); } @UiThread void onTraversal(boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) { final boolean hasImeFocus = updateImeFocusable(windowAttribute, false /* force */); if (!hasWindowFocus || isInLocalFocusMode(windowAttribute)) { return; } if (hasImeFocus == mHasImeFocus) { return; } mHasImeFocus = hasImeFocus; if (mHasImeFocus) { onPreWindowFocus(true /* hasWindowFocus */, windowAttribute); onPostWindowFocus(mViewRootImpl.mView.findFocus(), true /* hasWindowFocus */, windowAttribute); } } @UiThread void onPreWindowFocus(boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) { if (!mHasImeFocus || isInLocalFocusMode(windowAttribute)) { return; } if (hasWindowFocus) { getImmDelegate().setCurrentRootView(mViewRootImpl); } } @UiThread boolean updateImeFocusable(WindowManager.LayoutParams windowAttribute, boolean force) { final boolean hasImeFocus = WindowManager.LayoutParams.mayUseInputMethod( windowAttribute.flags); if (force) { mHasImeFocus = hasImeFocus; } return hasImeFocus; } @UiThread void onPostWindowFocus(View focusedView, boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) { if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) { return; } if (DEBUG) { Log.v(TAG, "onWindowFocus: " + focusedView + " softInputMode=" + InputMethodDebug.softInputModeToString( windowAttribute.softInputMode)); } boolean forceFocus = false; if (getImmDelegate().isRestartOnNextWindowFocus(true /* reset */)) { if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true"); forceFocus = true; } // Update mNextServedView when focusedView changed. final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; onViewFocusChanged(viewForWindowFocus, true); getImmDelegate().startInputAsyncOnWindowFocusGain(viewForWindowFocus, windowAttribute.softInputMode, windowAttribute.flags, forceFocus); } public boolean checkFocus(boolean forceNewFocus, boolean startInput) { if (!getImmDelegate().isCurrentRootView(mViewRootImpl) || (mServedView == mNextServedView && !forceNewFocus)) { return false; } if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView + " next=" + mNextServedView + " force=" + forceNewFocus + " package=" + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>")); // Close the connection when no next served view coming. if (mNextServedView == null) { getImmDelegate().finishInput(); getImmDelegate().closeCurrentIme(); return false; } mServedView = mNextServedView; getImmDelegate().finishComposingText(); if (startInput) { getImmDelegate().startInput(StartInputReason.CHECK_FOCUS, null, 0, 0, 0); } return true; } @UiThread void onViewFocusChanged(View view, boolean hasFocus) { if (view == null || view.isTemporarilyDetached()) { return; } if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) { return; } if (mServedView == view || !view.hasImeFocus() || !view.hasWindowFocus()) { return; } mNextServedView = hasFocus ? view : null; mViewRootImpl.dispatchCheckFocus(); } @UiThread void onViewDetachedFromWindow(View view) { if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) { return; } if (mServedView == view) { mNextServedView = null; mViewRootImpl.dispatchCheckFocus(); } } @UiThread void onWindowDismissed() { if (!getImmDelegate().isCurrentRootView(mViewRootImpl)) { return; } if (mServedView != null) { getImmDelegate().finishInput(); } getImmDelegate().setCurrentRootView(null); mHasImeFocus = false; } /** * @param windowAttribute {@link WindowManager.LayoutParams} to be checked. * @return Whether the window is in local focus mode or not. */ @AnyThread private static boolean isInLocalFocusMode(WindowManager.LayoutParams windowAttribute) { return (windowAttribute.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0; } int onProcessImeInputStage(Object token, InputEvent event, WindowManager.LayoutParams windowAttribute, InputMethodManager.FinishedInputEventCallback callback) { if (!mHasImeFocus || isInLocalFocusMode(windowAttribute)) { return InputMethodManager.DISPATCH_NOT_HANDLED; } final InputMethodManager imm = mViewRootImpl.mContext.getSystemService(InputMethodManager.class); if (imm == null) { return InputMethodManager.DISPATCH_NOT_HANDLED; } return imm.dispatchInputEvent(event, token, callback, mViewRootImpl.mHandler); } /** * A delegate implementing some basic {@link InputMethodManager} APIs. * @hide */ public interface InputMethodManagerDelegate { boolean startInput(@StartInputReason int startInputReason, View focusedView, @StartInputFlags int startInputFlags, @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags); void startInputAsyncOnWindowFocusGain(View rootView, @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus); void finishInput(); void closeCurrentIme(); void finishComposingText(); void setCurrentRootView(ViewRootImpl rootView); boolean isCurrentRootView(ViewRootImpl rootView); boolean isRestartOnNextWindowFocus(boolean reset); } public View getServedView() { return mServedView; } public View getNextServedView() { return mNextServedView; } public void setServedView(View view) { mServedView = view; } public void setNextServedView(View view) { mNextServedView = view; } } core/java/android/view/View.java +27 −24 Original line number Diff line number Diff line Loading @@ -130,7 +130,6 @@ import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.view.inspector.InspectableProperty; import android.view.inspector.InspectableProperty.EnumEntry; import android.view.inspector.InspectableProperty.FlagEntry; Loading Loading @@ -7942,12 +7941,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (isPressed()) { setPressed(false); } if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { notifyFocusChangeToInputMethodManager(false /* hasFocus */); if (hasWindowFocus()) { notifyFocusChangeToImeFocusController(false /* hasFocus */); } onFocusLost(); } else if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { notifyFocusChangeToInputMethodManager(true /* hasFocus */); } else if (hasWindowFocus()) { notifyFocusChangeToImeFocusController(true /* hasFocus */); } invalidate(true); Loading @@ -7964,23 +7963,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** * Notify {@link InputMethodManager} about the focus change of the {@link View}. * * <p>Does nothing when {@link InputMethodManager} is not available.</p> * Notify {@link ImeFocusController} about the focus change of the {@link View}. * * @param hasFocus {@code true} when the {@link View} is being focused. */ private void notifyFocusChangeToInputMethodManager(boolean hasFocus) { final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); if (imm == null) { private void notifyFocusChangeToImeFocusController(boolean hasFocus) { if (mAttachInfo == null) { return; } if (hasFocus) { imm.focusIn(this); } else { imm.focusOut(this); } mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); } /** @hide */ Loading Loading @@ -13918,7 +13909,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; onFinishTemporaryDetach(); if (hasWindowFocus() && hasFocus()) { notifyFocusChangeToInputMethodManager(true /* hasFocus */); notifyFocusChangeToImeFocusController(true /* hasFocus */); } notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); Loading Loading @@ -14326,13 +14317,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { notifyFocusChangeToInputMethodManager(false /* hasFocus */); notifyFocusChangeToImeFocusController(false /* hasFocus */); } removeLongPressCallback(); removeTapCallback(); onFocusLost(); } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { notifyFocusChangeToInputMethodManager(true /* hasFocus */); notifyFocusChangeToImeFocusController(true /* hasFocus */); } refreshDrawableState(); Loading @@ -14348,6 +14339,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mAttachInfo != null && mAttachInfo.mHasWindowFocus; } /** * @return {@code true} if this view is in a window that currently has IME focusable state. * @hide */ public boolean hasImeFocus() { return mAttachInfo != null && mAttachInfo.mHasImeFocus; } /** * Dispatch a view visibility change down the view hierarchy. * ViewGroups should override to route to their children. Loading Loading @@ -19644,7 +19643,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, rebuildOutline(); if (isFocused()) { notifyFocusChangeToInputMethodManager(true /* hasFocus */); notifyFocusChangeToImeFocusController(true /* hasFocus */); } } Loading Loading @@ -20227,9 +20226,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onDetachedFromWindow(); onDetachedFromWindowInternal(); InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); if (imm != null) { imm.onViewDetachedFromWindow(this); if (info != null) { info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); } ListenerInfo li = mListenerInfo; Loading Loading @@ -28564,6 +28562,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @UnsupportedAppUsage boolean mHasWindowFocus; /** * Indicates whether the view's window has IME focused. */ boolean mHasImeFocus; /** * The current visibility of the window. */ core/java/android/view/ViewRootImpl.java +32 −50 Original line number Diff line number Diff line Loading @@ -453,7 +453,6 @@ public final class ViewRootImpl implements ViewParent, boolean mReportNextDraw; boolean mFullRedrawNeeded; boolean mNewSurfaceNeeded; boolean mLastWasImTarget; boolean mForceNextWindowRelayout; CountDownLatch mWindowDrawCountDown; Loading Loading @@ -619,6 +618,16 @@ public final class ViewRootImpl implements ViewParent, InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, 0) : null; private final ImeFocusController mImeFocusController; /** * @return {@link ImeFocusController} for this instance. */ @NonNull public ImeFocusController getImeFocusController() { return mImeFocusController; } private final InsetsController mInsetsController = new InsetsController(this); private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker(); Loading Loading @@ -704,6 +713,7 @@ public final class ViewRootImpl implements ViewParent, } loadSystemProperties(); mImeFocusController = new ImeFocusController(this); } public static void addFirstDrawHandler(Runnable callback) { Loading Loading @@ -1054,11 +1064,6 @@ public final class ViewRootImpl implements ViewParent, } } /** Whether the window is in local focus mode or not */ private boolean isInLocalFocusMode() { return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0; } @UnsupportedAppUsage public int getWindowFlags() { return mWindowAttributes.flags; Loading Loading @@ -2892,19 +2897,7 @@ public final class ViewRootImpl implements ViewParent, mViewVisibility = viewVisibility; mHadWindowFocus = hasWindowFocus; if (hasWindowFocus && !isInLocalFocusMode()) { final boolean imTarget = WindowManager.LayoutParams .mayUseInputMethod(mWindowAttributes.flags); if (imTarget != mLastWasImTarget) { mLastWasImTarget = imTarget; InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); if (imm != null && imTarget) { imm.onPreWindowFocus(mView, hasWindowFocus); imm.onPostWindowFocus(mView, mView.findFocus(), mWindowAttributes.softInputMode, mWindowAttributes.flags); } } } mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); // Remember if we must report the next draw. if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { Loading Loading @@ -3072,14 +3065,10 @@ public final class ViewRootImpl implements ViewParent, } mAttachInfo.mHasWindowFocus = hasWindowFocus; mAttachInfo.mHasImeFocus = mImeFocusController.updateImeFocusable( mWindowAttributes, true /* force */); mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes); mLastWasImTarget = WindowManager.LayoutParams .mayUseInputMethod(mWindowAttributes.flags); InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) { imm.onPreWindowFocus(mView, hasWindowFocus); } if (mView != null) { mAttachInfo.mKeyDispatchState.reset(); mView.dispatchWindowFocusChanged(hasWindowFocus); Loading @@ -3091,11 +3080,10 @@ public final class ViewRootImpl implements ViewParent, // Note: must be done after the focus change callbacks, // so all of the view state is set up correctly. mImeFocusController.onPostWindowFocus(mView.findFocus(), hasWindowFocus, mWindowAttributes); if (hasWindowFocus) { if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) { imm.onPostWindowFocus(mView, mView.findFocus(), mWindowAttributes.softInputMode, mWindowAttributes.flags); } // Clear the forward bit. We can just do this directly, since // the window manager doesn't care about it. mWindowAttributes.softInputMode &= Loading Loading @@ -4891,10 +4879,7 @@ public final class ViewRootImpl implements ViewParent, enqueueInputEvent(event, null, 0, true); } break; case MSG_CHECK_FOCUS: { InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); if (imm != null) { imm.checkFocus(); } getImeFocusController().checkFocus(false, true); } break; case MSG_CLOSE_SYSTEM_DIALOGS: { if (mView != null) { Loading Loading @@ -5458,23 +5443,20 @@ public final class ViewRootImpl implements ViewParent, @Override protected int onProcess(QueuedInputEvent q) { if (mLastWasImTarget && !isInLocalFocusMode()) { InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); if (imm != null) { final InputEvent event = q.mEvent; if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event); int result = imm.dispatchInputEvent(event, q, this, mHandler); if (result == InputMethodManager.DISPATCH_HANDLED) { return FINISH_HANDLED; } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) { final int result = mImeFocusController.onProcessImeInputStage( q, q.mEvent, mWindowAttributes, this); switch (result) { case InputMethodManager.DISPATCH_IN_PROGRESS: // callback will be invoked later return DEFER; case InputMethodManager.DISPATCH_NOT_HANDLED: // The IME could not handle it, so skip along to the next InputStage return FORWARD; } else { return DEFER; // callback will be invoked later } } case InputMethodManager.DISPATCH_HANDLED: return FINISH_HANDLED; default: throw new IllegalStateException("Unexpected result=" + result); } return FORWARD; } @Override Loading core/java/android/view/WindowManagerGlobal.java +2 −5 Original line number Diff line number Diff line Loading @@ -487,11 +487,8 @@ public final class WindowManagerGlobal { ViewRootImpl root = mRoots.get(index); View view = root.getView(); if (view != null) { InputMethodManager imm = view.getContext().getSystemService(InputMethodManager.class); if (imm != null) { imm.windowDismissed(mViews.get(index).getWindowToken()); } if (root != null) { root.getImeFocusController().onWindowDismissed(); } boolean deferred = root.die(immediate); if (view != null) { Loading core/java/android/view/inputmethod/BaseInputConnection.java +3 −2 Original line number Diff line number Diff line Loading @@ -758,8 +758,9 @@ public class BaseInputConnection implements InputConnection { Context context; if (mTargetView != null) { context = mTargetView.getContext(); } else if (mIMM.mServedView != null) { context = mIMM.mServedView.getContext(); } else if (mIMM.mCurRootView != null) { final View servedView = mIMM.mCurRootView.getImeFocusController().getServedView(); context = servedView != null ? servedView.getContext() : null; } else { context = null; } Loading Loading
core/java/android/view/ImeFocusController.java 0 → 100644 +234 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.view; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.UiThread; import android.util.Log; import android.view.inputmethod.InputMethodManager; import com.android.internal.inputmethod.InputMethodDebug; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; /** * Responsible for IME focus handling inside {@link ViewRootImpl}. * @hide */ public final class ImeFocusController { private static final boolean DEBUG = false; private static final String TAG = "ImeFocusController"; private final ViewRootImpl mViewRootImpl; private boolean mHasImeFocus = false; private View mServedView; private View mNextServedView; @UiThread ImeFocusController(@NonNull ViewRootImpl viewRootImpl) { mViewRootImpl = viewRootImpl; } private InputMethodManagerDelegate getImmDelegate() { return mViewRootImpl.mContext.getSystemService(InputMethodManager.class).getDelegate(); } @UiThread void onTraversal(boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) { final boolean hasImeFocus = updateImeFocusable(windowAttribute, false /* force */); if (!hasWindowFocus || isInLocalFocusMode(windowAttribute)) { return; } if (hasImeFocus == mHasImeFocus) { return; } mHasImeFocus = hasImeFocus; if (mHasImeFocus) { onPreWindowFocus(true /* hasWindowFocus */, windowAttribute); onPostWindowFocus(mViewRootImpl.mView.findFocus(), true /* hasWindowFocus */, windowAttribute); } } @UiThread void onPreWindowFocus(boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) { if (!mHasImeFocus || isInLocalFocusMode(windowAttribute)) { return; } if (hasWindowFocus) { getImmDelegate().setCurrentRootView(mViewRootImpl); } } @UiThread boolean updateImeFocusable(WindowManager.LayoutParams windowAttribute, boolean force) { final boolean hasImeFocus = WindowManager.LayoutParams.mayUseInputMethod( windowAttribute.flags); if (force) { mHasImeFocus = hasImeFocus; } return hasImeFocus; } @UiThread void onPostWindowFocus(View focusedView, boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) { if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) { return; } if (DEBUG) { Log.v(TAG, "onWindowFocus: " + focusedView + " softInputMode=" + InputMethodDebug.softInputModeToString( windowAttribute.softInputMode)); } boolean forceFocus = false; if (getImmDelegate().isRestartOnNextWindowFocus(true /* reset */)) { if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true"); forceFocus = true; } // Update mNextServedView when focusedView changed. final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; onViewFocusChanged(viewForWindowFocus, true); getImmDelegate().startInputAsyncOnWindowFocusGain(viewForWindowFocus, windowAttribute.softInputMode, windowAttribute.flags, forceFocus); } public boolean checkFocus(boolean forceNewFocus, boolean startInput) { if (!getImmDelegate().isCurrentRootView(mViewRootImpl) || (mServedView == mNextServedView && !forceNewFocus)) { return false; } if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView + " next=" + mNextServedView + " force=" + forceNewFocus + " package=" + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>")); // Close the connection when no next served view coming. if (mNextServedView == null) { getImmDelegate().finishInput(); getImmDelegate().closeCurrentIme(); return false; } mServedView = mNextServedView; getImmDelegate().finishComposingText(); if (startInput) { getImmDelegate().startInput(StartInputReason.CHECK_FOCUS, null, 0, 0, 0); } return true; } @UiThread void onViewFocusChanged(View view, boolean hasFocus) { if (view == null || view.isTemporarilyDetached()) { return; } if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) { return; } if (mServedView == view || !view.hasImeFocus() || !view.hasWindowFocus()) { return; } mNextServedView = hasFocus ? view : null; mViewRootImpl.dispatchCheckFocus(); } @UiThread void onViewDetachedFromWindow(View view) { if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) { return; } if (mServedView == view) { mNextServedView = null; mViewRootImpl.dispatchCheckFocus(); } } @UiThread void onWindowDismissed() { if (!getImmDelegate().isCurrentRootView(mViewRootImpl)) { return; } if (mServedView != null) { getImmDelegate().finishInput(); } getImmDelegate().setCurrentRootView(null); mHasImeFocus = false; } /** * @param windowAttribute {@link WindowManager.LayoutParams} to be checked. * @return Whether the window is in local focus mode or not. */ @AnyThread private static boolean isInLocalFocusMode(WindowManager.LayoutParams windowAttribute) { return (windowAttribute.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0; } int onProcessImeInputStage(Object token, InputEvent event, WindowManager.LayoutParams windowAttribute, InputMethodManager.FinishedInputEventCallback callback) { if (!mHasImeFocus || isInLocalFocusMode(windowAttribute)) { return InputMethodManager.DISPATCH_NOT_HANDLED; } final InputMethodManager imm = mViewRootImpl.mContext.getSystemService(InputMethodManager.class); if (imm == null) { return InputMethodManager.DISPATCH_NOT_HANDLED; } return imm.dispatchInputEvent(event, token, callback, mViewRootImpl.mHandler); } /** * A delegate implementing some basic {@link InputMethodManager} APIs. * @hide */ public interface InputMethodManagerDelegate { boolean startInput(@StartInputReason int startInputReason, View focusedView, @StartInputFlags int startInputFlags, @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags); void startInputAsyncOnWindowFocusGain(View rootView, @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus); void finishInput(); void closeCurrentIme(); void finishComposingText(); void setCurrentRootView(ViewRootImpl rootView); boolean isCurrentRootView(ViewRootImpl rootView); boolean isRestartOnNextWindowFocus(boolean reset); } public View getServedView() { return mServedView; } public View getNextServedView() { return mNextServedView; } public void setServedView(View view) { mServedView = view; } public void setNextServedView(View view) { mNextServedView = view; } }
core/java/android/view/View.java +27 −24 Original line number Diff line number Diff line Loading @@ -130,7 +130,6 @@ import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.view.inspector.InspectableProperty; import android.view.inspector.InspectableProperty.EnumEntry; import android.view.inspector.InspectableProperty.FlagEntry; Loading Loading @@ -7942,12 +7941,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (isPressed()) { setPressed(false); } if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { notifyFocusChangeToInputMethodManager(false /* hasFocus */); if (hasWindowFocus()) { notifyFocusChangeToImeFocusController(false /* hasFocus */); } onFocusLost(); } else if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { notifyFocusChangeToInputMethodManager(true /* hasFocus */); } else if (hasWindowFocus()) { notifyFocusChangeToImeFocusController(true /* hasFocus */); } invalidate(true); Loading @@ -7964,23 +7963,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** * Notify {@link InputMethodManager} about the focus change of the {@link View}. * * <p>Does nothing when {@link InputMethodManager} is not available.</p> * Notify {@link ImeFocusController} about the focus change of the {@link View}. * * @param hasFocus {@code true} when the {@link View} is being focused. */ private void notifyFocusChangeToInputMethodManager(boolean hasFocus) { final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); if (imm == null) { private void notifyFocusChangeToImeFocusController(boolean hasFocus) { if (mAttachInfo == null) { return; } if (hasFocus) { imm.focusIn(this); } else { imm.focusOut(this); } mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); } /** @hide */ Loading Loading @@ -13918,7 +13909,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; onFinishTemporaryDetach(); if (hasWindowFocus() && hasFocus()) { notifyFocusChangeToInputMethodManager(true /* hasFocus */); notifyFocusChangeToImeFocusController(true /* hasFocus */); } notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); Loading Loading @@ -14326,13 +14317,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { notifyFocusChangeToInputMethodManager(false /* hasFocus */); notifyFocusChangeToImeFocusController(false /* hasFocus */); } removeLongPressCallback(); removeTapCallback(); onFocusLost(); } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { notifyFocusChangeToInputMethodManager(true /* hasFocus */); notifyFocusChangeToImeFocusController(true /* hasFocus */); } refreshDrawableState(); Loading @@ -14348,6 +14339,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mAttachInfo != null && mAttachInfo.mHasWindowFocus; } /** * @return {@code true} if this view is in a window that currently has IME focusable state. * @hide */ public boolean hasImeFocus() { return mAttachInfo != null && mAttachInfo.mHasImeFocus; } /** * Dispatch a view visibility change down the view hierarchy. * ViewGroups should override to route to their children. Loading Loading @@ -19644,7 +19643,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, rebuildOutline(); if (isFocused()) { notifyFocusChangeToInputMethodManager(true /* hasFocus */); notifyFocusChangeToImeFocusController(true /* hasFocus */); } } Loading Loading @@ -20227,9 +20226,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onDetachedFromWindow(); onDetachedFromWindowInternal(); InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); if (imm != null) { imm.onViewDetachedFromWindow(this); if (info != null) { info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); } ListenerInfo li = mListenerInfo; Loading Loading @@ -28564,6 +28562,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @UnsupportedAppUsage boolean mHasWindowFocus; /** * Indicates whether the view's window has IME focused. */ boolean mHasImeFocus; /** * The current visibility of the window. */
core/java/android/view/ViewRootImpl.java +32 −50 Original line number Diff line number Diff line Loading @@ -453,7 +453,6 @@ public final class ViewRootImpl implements ViewParent, boolean mReportNextDraw; boolean mFullRedrawNeeded; boolean mNewSurfaceNeeded; boolean mLastWasImTarget; boolean mForceNextWindowRelayout; CountDownLatch mWindowDrawCountDown; Loading Loading @@ -619,6 +618,16 @@ public final class ViewRootImpl implements ViewParent, InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, 0) : null; private final ImeFocusController mImeFocusController; /** * @return {@link ImeFocusController} for this instance. */ @NonNull public ImeFocusController getImeFocusController() { return mImeFocusController; } private final InsetsController mInsetsController = new InsetsController(this); private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker(); Loading Loading @@ -704,6 +713,7 @@ public final class ViewRootImpl implements ViewParent, } loadSystemProperties(); mImeFocusController = new ImeFocusController(this); } public static void addFirstDrawHandler(Runnable callback) { Loading Loading @@ -1054,11 +1064,6 @@ public final class ViewRootImpl implements ViewParent, } } /** Whether the window is in local focus mode or not */ private boolean isInLocalFocusMode() { return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0; } @UnsupportedAppUsage public int getWindowFlags() { return mWindowAttributes.flags; Loading Loading @@ -2892,19 +2897,7 @@ public final class ViewRootImpl implements ViewParent, mViewVisibility = viewVisibility; mHadWindowFocus = hasWindowFocus; if (hasWindowFocus && !isInLocalFocusMode()) { final boolean imTarget = WindowManager.LayoutParams .mayUseInputMethod(mWindowAttributes.flags); if (imTarget != mLastWasImTarget) { mLastWasImTarget = imTarget; InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); if (imm != null && imTarget) { imm.onPreWindowFocus(mView, hasWindowFocus); imm.onPostWindowFocus(mView, mView.findFocus(), mWindowAttributes.softInputMode, mWindowAttributes.flags); } } } mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); // Remember if we must report the next draw. if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { Loading Loading @@ -3072,14 +3065,10 @@ public final class ViewRootImpl implements ViewParent, } mAttachInfo.mHasWindowFocus = hasWindowFocus; mAttachInfo.mHasImeFocus = mImeFocusController.updateImeFocusable( mWindowAttributes, true /* force */); mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes); mLastWasImTarget = WindowManager.LayoutParams .mayUseInputMethod(mWindowAttributes.flags); InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) { imm.onPreWindowFocus(mView, hasWindowFocus); } if (mView != null) { mAttachInfo.mKeyDispatchState.reset(); mView.dispatchWindowFocusChanged(hasWindowFocus); Loading @@ -3091,11 +3080,10 @@ public final class ViewRootImpl implements ViewParent, // Note: must be done after the focus change callbacks, // so all of the view state is set up correctly. mImeFocusController.onPostWindowFocus(mView.findFocus(), hasWindowFocus, mWindowAttributes); if (hasWindowFocus) { if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) { imm.onPostWindowFocus(mView, mView.findFocus(), mWindowAttributes.softInputMode, mWindowAttributes.flags); } // Clear the forward bit. We can just do this directly, since // the window manager doesn't care about it. mWindowAttributes.softInputMode &= Loading Loading @@ -4891,10 +4879,7 @@ public final class ViewRootImpl implements ViewParent, enqueueInputEvent(event, null, 0, true); } break; case MSG_CHECK_FOCUS: { InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); if (imm != null) { imm.checkFocus(); } getImeFocusController().checkFocus(false, true); } break; case MSG_CLOSE_SYSTEM_DIALOGS: { if (mView != null) { Loading Loading @@ -5458,23 +5443,20 @@ public final class ViewRootImpl implements ViewParent, @Override protected int onProcess(QueuedInputEvent q) { if (mLastWasImTarget && !isInLocalFocusMode()) { InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); if (imm != null) { final InputEvent event = q.mEvent; if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event); int result = imm.dispatchInputEvent(event, q, this, mHandler); if (result == InputMethodManager.DISPATCH_HANDLED) { return FINISH_HANDLED; } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) { final int result = mImeFocusController.onProcessImeInputStage( q, q.mEvent, mWindowAttributes, this); switch (result) { case InputMethodManager.DISPATCH_IN_PROGRESS: // callback will be invoked later return DEFER; case InputMethodManager.DISPATCH_NOT_HANDLED: // The IME could not handle it, so skip along to the next InputStage return FORWARD; } else { return DEFER; // callback will be invoked later } } case InputMethodManager.DISPATCH_HANDLED: return FINISH_HANDLED; default: throw new IllegalStateException("Unexpected result=" + result); } return FORWARD; } @Override Loading
core/java/android/view/WindowManagerGlobal.java +2 −5 Original line number Diff line number Diff line Loading @@ -487,11 +487,8 @@ public final class WindowManagerGlobal { ViewRootImpl root = mRoots.get(index); View view = root.getView(); if (view != null) { InputMethodManager imm = view.getContext().getSystemService(InputMethodManager.class); if (imm != null) { imm.windowDismissed(mViews.get(index).getWindowToken()); } if (root != null) { root.getImeFocusController().onWindowDismissed(); } boolean deferred = root.die(immediate); if (view != null) { Loading
core/java/android/view/inputmethod/BaseInputConnection.java +3 −2 Original line number Diff line number Diff line Loading @@ -758,8 +758,9 @@ public class BaseInputConnection implements InputConnection { Context context; if (mTargetView != null) { context = mTargetView.getContext(); } else if (mIMM.mServedView != null) { context = mIMM.mServedView.getContext(); } else if (mIMM.mCurRootView != null) { final View servedView = mIMM.mCurRootView.getImeFocusController().getServedView(); context = servedView != null ? servedView.getContext() : null; } else { context = null; } Loading