Search in sources :

Example 11 with InputBindResult

use of com.android.internal.view.InputBindResult in project platform_frameworks_base by android.

the class InputMethodManagerService method startInputUncheckedLocked.

InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext, /* @InputConnectionInspector.missingMethods */
final int missingMethods, @NonNull EditorInfo attribute, int controlFlags) {
    // If no method is currently selected, do nothing.
    if (mCurMethodId == null) {
        return mNoBinding;
    }
    if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid, attribute.packageName)) {
        Slog.e(TAG, "Rejecting this client as it reported an invalid package name." + " uid=" + cs.uid + " package=" + attribute.packageName);
        return mNoBinding;
    }
    if (mCurClient != cs) {
        // Was the keyguard locked when switching over to the new client?
        mCurClientInKeyguard = isKeyguardLocked();
        // If the client is changing, we need to switch over to the new
        // one.
        unbindCurrentClientLocked(InputMethodClient.UNBIND_REASON_SWITCH_CLIENT);
        if (DEBUG)
            Slog.v(TAG, "switching to client: client=" + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
        // If the screen is on, inform the new client it is active
        if (mIsInteractive) {
            executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, cs));
        }
    }
    // Bump up the sequence for this client and attach it.
    mCurSeq++;
    if (mCurSeq <= 0)
        mCurSeq = 1;
    mCurClient = cs;
    mCurInputContext = inputContext;
    mCurInputContextMissingMethods = missingMethods;
    mCurAttribute = attribute;
    // Check if the input method is changing.
    if (mCurId != null && mCurId.equals(mCurMethodId)) {
        if (cs.curSession != null) {
            // then just return it.
            return attachNewInputLocked((controlFlags & InputMethodManager.CONTROL_START_INITIAL) != 0);
        }
        if (mHaveConnection) {
            if (mCurMethod != null) {
                // Return to client, and we will get back with it when
                // we have had a session made for it.
                requestClientSessionLocked(cs);
                return new InputBindResult(null, null, mCurId, mCurSeq, mCurUserActionNotificationSequenceNumber);
            } else if (SystemClock.uptimeMillis() < (mLastBindTime + TIME_TO_RECONNECT)) {
                // to see if we can get back in touch with the service.
                return new InputBindResult(null, null, mCurId, mCurSeq, mCurUserActionNotificationSequenceNumber);
            } else {
                EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId, SystemClock.uptimeMillis() - mLastBindTime, 0);
            }
        }
    }
    return startInputInnerLocked();
}
Also used : InputBindResult(com.android.internal.view.InputBindResult)

Example 12 with InputBindResult

use of com.android.internal.view.InputBindResult in project platform_frameworks_base by android.

the class InputMethodManager method startInputInner.

boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason, IBinder windowGainingFocus, int controlFlags, int softInputMode, int windowFlags) {
    final View view;
    synchronized (mH) {
        view = mServedView;
        // Make sure we have a window token for the served view.
        if (DEBUG) {
            Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) + " reason=" + InputMethodClient.getStartInputReason(startInputReason));
        }
        if (view == null) {
            if (DEBUG)
                Log.v(TAG, "ABORT input: no served view!");
            return false;
        }
    }
    // Now we need to get an input connection from the served view.
    // This is complicated in a couple ways: we can't be holding our lock
    // when calling out to the view, and we need to make sure we call into
    // the view on the same thread that is driving its view hierarchy.
    Handler vh = view.getHandler();
    if (vh == null) {
        // screen without a connection.
        if (DEBUG)
            Log.v(TAG, "ABORT input: no handler for view! Close current input.");
        closeCurrentInput();
        return false;
    }
    if (vh.getLooper() != Looper.myLooper()) {
        // we need to reschedule our work for over there.
        if (DEBUG)
            Log.v(TAG, "Starting input: reschedule to view thread");
        vh.post(new Runnable() {

            @Override
            public void run() {
                startInputInner(startInputReason, null, 0, 0, 0);
            }
        });
        return false;
    }
    // Okay we are now ready to call into the served view and have it
    // do its stuff.
    // Life is good: let's hook everything up!
    EditorInfo tba = new EditorInfo();
    // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the
    // system can verify the consistency between the uid of this process and package name passed
    // from here. See comment of Context#getOpPackageName() for details.
    tba.packageName = view.getContext().getOpPackageName();
    tba.fieldId = view.getId();
    InputConnection ic = view.onCreateInputConnection(tba);
    if (DEBUG)
        Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
    synchronized (mH) {
        // changed.
        if (mServedView != view || !mServedConnecting) {
            // Something else happened, so abort.
            if (DEBUG)
                Log.v(TAG, "Starting input: finished by someone else. view=" + dumpViewInfo(view) + " mServedView=" + dumpViewInfo(mServedView) + " mServedConnecting=" + mServedConnecting);
            return false;
        }
        // connected so we want to restart it.
        if (mCurrentTextBoxAttribute == null) {
            controlFlags |= CONTROL_START_INITIAL;
        }
        // Hook 'em up and let 'er rip.
        mCurrentTextBoxAttribute = tba;
        mServedConnecting = false;
        if (mServedInputConnectionWrapper != null) {
            mServedInputConnectionWrapper.deactivate();
            mServedInputConnectionWrapper = null;
        }
        ControlledInputConnectionWrapper servedContext;
        final int missingMethodFlags;
        if (ic != null) {
            mCursorSelStart = tba.initialSelStart;
            mCursorSelEnd = tba.initialSelEnd;
            mCursorCandStart = -1;
            mCursorCandEnd = -1;
            mCursorRect.setEmpty();
            mCursorAnchorInfo = null;
            final Handler icHandler;
            missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
            if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER) != 0) {
                // InputConnection#getHandler() is not implemented.
                icHandler = null;
            } else {
                icHandler = ic.getHandler();
            }
            servedContext = new ControlledInputConnectionWrapper(icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
        } else {
            servedContext = null;
            missingMethodFlags = 0;
        }
        mServedInputConnectionWrapper = servedContext;
        try {
            if (DEBUG)
                Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic=" + ic + " tba=" + tba + " controlFlags=#" + Integer.toHexString(controlFlags));
            final InputBindResult res = mService.startInputOrWindowGainedFocus(startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode, windowFlags, tba, servedContext, missingMethodFlags);
            if (DEBUG)
                Log.v(TAG, "Starting input: Bind result=" + res);
            if (res != null) {
                if (res.id != null) {
                    setInputChannelLocked(res.channel);
                    mBindSequence = res.sequence;
                    mCurMethod = res.method;
                    mCurId = res.id;
                    mNextUserActionNotificationSequenceNumber = res.userActionNotificationSequenceNumber;
                    if (mServedInputConnectionWrapper != null) {
                        mServedInputConnectionWrapper.setInputMethodId(mCurId);
                    }
                } else {
                    if (res.channel != null && res.channel != mCurChannel) {
                        res.channel.dispose();
                    }
                    if (mCurMethod == null) {
                        // This means there is no input method available.
                        if (DEBUG)
                            Log.v(TAG, "ABORT input: no input method!");
                        return true;
                    }
                }
            } else {
                if (startInputReason == InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN) {
                    // TODO: InputBindResult should have the error code.
                    if (DEBUG)
                        Log.w(TAG, "startInputOrWindowGainedFocus failed. " + "Window focus may have already been lost. " + "win=" + windowGainingFocus + " view=" + dumpViewInfo(view));
                    if (!mActive) {
                        // mHasBeenInactive is a latch switch to forcefully refresh IME focus
                        // state when an inactive (mActive == false) client is gaining window
                        // focus. In case we have unnecessary disable the latch due to this
                        // spurious wakeup, we re-enable the latch here.
                        // TODO: Come up with more robust solution.
                        mHasBeenInactive = true;
                    }
                }
            }
            if (mCurMethod != null && mCompletions != null) {
                try {
                    mCurMethod.displayCompletions(mCompletions);
                } catch (RemoteException e) {
                }
            }
        } catch (RemoteException e) {
            Log.w(TAG, "IME died: " + mCurId, e);
        }
    }
    return true;
}
Also used : InputBindResult(com.android.internal.view.InputBindResult) Handler(android.os.Handler) RemoteException(android.os.RemoteException) View(android.view.View)

Example 13 with InputBindResult

use of com.android.internal.view.InputBindResult in project android_frameworks_base by crdroidandroid.

the class InputMethodManager method startInputInner.

boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason, IBinder windowGainingFocus, int controlFlags, int softInputMode, int windowFlags) {
    final View view;
    synchronized (mH) {
        view = mServedView;
        // Make sure we have a window token for the served view.
        if (DEBUG) {
            Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) + " reason=" + InputMethodClient.getStartInputReason(startInputReason));
        }
        if (view == null) {
            if (DEBUG)
                Log.v(TAG, "ABORT input: no served view!");
            return false;
        }
    }
    // Now we need to get an input connection from the served view.
    // This is complicated in a couple ways: we can't be holding our lock
    // when calling out to the view, and we need to make sure we call into
    // the view on the same thread that is driving its view hierarchy.
    Handler vh = view.getHandler();
    if (vh == null) {
        // screen without a connection.
        if (DEBUG)
            Log.v(TAG, "ABORT input: no handler for view! Close current input.");
        closeCurrentInput();
        return false;
    }
    if (vh.getLooper() != Looper.myLooper()) {
        // we need to reschedule our work for over there.
        if (DEBUG)
            Log.v(TAG, "Starting input: reschedule to view thread");
        vh.post(new Runnable() {

            @Override
            public void run() {
                startInputInner(startInputReason, null, 0, 0, 0);
            }
        });
        return false;
    }
    // Okay we are now ready to call into the served view and have it
    // do its stuff.
    // Life is good: let's hook everything up!
    EditorInfo tba = new EditorInfo();
    // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the
    // system can verify the consistency between the uid of this process and package name passed
    // from here. See comment of Context#getOpPackageName() for details.
    tba.packageName = view.getContext().getOpPackageName();
    tba.fieldId = view.getId();
    InputConnection ic = view.onCreateInputConnection(tba);
    if (DEBUG)
        Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
    synchronized (mH) {
        // changed.
        if (mServedView != view || !mServedConnecting) {
            // Something else happened, so abort.
            if (DEBUG)
                Log.v(TAG, "Starting input: finished by someone else. view=" + dumpViewInfo(view) + " mServedView=" + dumpViewInfo(mServedView) + " mServedConnecting=" + mServedConnecting);
            return false;
        }
        // connected so we want to restart it.
        if (mCurrentTextBoxAttribute == null) {
            controlFlags |= CONTROL_START_INITIAL;
        }
        // Hook 'em up and let 'er rip.
        mCurrentTextBoxAttribute = tba;
        mServedConnecting = false;
        if (mServedInputConnectionWrapper != null) {
            mServedInputConnectionWrapper.deactivate();
            mServedInputConnectionWrapper = null;
        }
        ControlledInputConnectionWrapper servedContext;
        final int missingMethodFlags;
        if (ic != null) {
            mCursorSelStart = tba.initialSelStart;
            mCursorSelEnd = tba.initialSelEnd;
            mCursorCandStart = -1;
            mCursorCandEnd = -1;
            mCursorRect.setEmpty();
            mCursorAnchorInfo = null;
            final Handler icHandler;
            missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
            if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER) != 0) {
                // InputConnection#getHandler() is not implemented.
                icHandler = null;
            } else {
                icHandler = ic.getHandler();
            }
            servedContext = new ControlledInputConnectionWrapper(icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
        } else {
            servedContext = null;
            missingMethodFlags = 0;
        }
        mServedInputConnectionWrapper = servedContext;
        try {
            if (DEBUG)
                Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic=" + ic + " tba=" + tba + " controlFlags=#" + Integer.toHexString(controlFlags));
            final InputBindResult res = mService.startInputOrWindowGainedFocus(startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode, windowFlags, tba, servedContext, missingMethodFlags);
            if (DEBUG)
                Log.v(TAG, "Starting input: Bind result=" + res);
            if (res != null) {
                if (res.id != null) {
                    setInputChannelLocked(res.channel);
                    mBindSequence = res.sequence;
                    mCurMethod = res.method;
                    mCurId = res.id;
                    mNextUserActionNotificationSequenceNumber = res.userActionNotificationSequenceNumber;
                    if (mServedInputConnectionWrapper != null) {
                        mServedInputConnectionWrapper.setInputMethodId(mCurId);
                    }
                } else {
                    if (res.channel != null && res.channel != mCurChannel) {
                        res.channel.dispose();
                    }
                    if (mCurMethod == null) {
                        // This means there is no input method available.
                        if (DEBUG)
                            Log.v(TAG, "ABORT input: no input method!");
                        return true;
                    }
                }
            } else {
                if (startInputReason == InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN) {
                    // TODO: InputBindResult should have the error code.
                    if (DEBUG)
                        Log.w(TAG, "startInputOrWindowGainedFocus failed. " + "Window focus may have already been lost. " + "win=" + windowGainingFocus + " view=" + dumpViewInfo(view));
                    if (!mActive) {
                        // mHasBeenInactive is a latch switch to forcefully refresh IME focus
                        // state when an inactive (mActive == false) client is gaining window
                        // focus. In case we have unnecessary disable the latch due to this
                        // spurious wakeup, we re-enable the latch here.
                        // TODO: Come up with more robust solution.
                        mHasBeenInactive = true;
                    }
                }
            }
            if (mCurMethod != null && mCompletions != null) {
                try {
                    mCurMethod.displayCompletions(mCompletions);
                } catch (RemoteException e) {
                }
            }
        } catch (RemoteException e) {
            Log.w(TAG, "IME died: " + mCurId, e);
        }
    }
    return true;
}
Also used : InputBindResult(com.android.internal.view.InputBindResult) Handler(android.os.Handler) RemoteException(android.os.RemoteException) View(android.view.View)

Example 14 with InputBindResult

use of com.android.internal.view.InputBindResult in project android_frameworks_base by crdroidandroid.

the class InputMethodManagerService method windowGainedFocus.

private InputBindResult windowGainedFocus(/* @InputMethodClient.StartInputReason */
final int startInputReason, IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode, int windowFlags, EditorInfo attribute, IInputContext inputContext, /* @InputConnectionInspector.missingMethods */
final int missingMethods) {
    // Needs to check the validity before clearing calling identity
    final boolean calledFromValidUser = calledFromValidUser();
    InputBindResult res = null;
    long ident = Binder.clearCallingIdentity();
    try {
        synchronized (mMethodMap) {
            if (DEBUG)
                Slog.v(TAG, "windowGainedFocus: reason=" + InputMethodClient.getStartInputReason(startInputReason) + " client=" + client.asBinder() + " inputContext=" + inputContext + " missingMethods=" + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods) + " attribute=" + attribute + " controlFlags=#" + Integer.toHexString(controlFlags) + " softInputMode=#" + Integer.toHexString(softInputMode) + " windowFlags=#" + Integer.toHexString(windowFlags));
            ClientState cs = mClients.get(client.asBinder());
            if (cs == null) {
                throw new IllegalArgumentException("unknown client " + client.asBinder());
            }
            try {
                if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
                    // Check with the window manager to make sure this client actually
                    // has a window with focus.  If not, reject.  This is thread safe
                    // because if the focus changes some time before or after, the
                    // next client receiving focus that has any interest in input will
                    // be calling through here after that change happens.
                    Slog.w(TAG, "Focus gain on non-focused client " + cs.client + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
                    return null;
                }
            } catch (RemoteException e) {
            }
            if (!calledFromValidUser) {
                Slog.w(TAG, "A background user is requesting window. Hiding IME.");
                Slog.w(TAG, "If you want to interect with IME, you need " + "android.permission.INTERACT_ACROSS_USERS_FULL");
                hideCurrentInputLocked(0, null);
                return null;
            }
            if (mCurFocusedWindow == windowToken) {
                Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client + " attribute=" + attribute + ", token = " + windowToken);
                if (attribute != null) {
                    return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute, controlFlags);
                }
                return null;
            }
            mCurFocusedWindow = windowToken;
            mCurFocusedWindowClient = cs;
            // Should we auto-show the IME even if the caller has not
            // specified what should be done with it?
            // We only do this automatically if the window can resize
            // to accommodate the IME (so what the user sees will give
            // them good context without input information being obscured
            // by the IME) or if running on a large screen where there
            // is more room for the target window + IME.
            final boolean doAutoShow = (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE || mRes.getConfiguration().isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
            final boolean isTextEditor = (controlFlags & InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR) != 0;
            // We want to start input before showing the IME, but after closing
            // it.  We want to do this after closing it to help the IME disappear
            // more quickly (not get stuck behind it initializing itself for the
            // new focused input, even if its window wants to hide the IME).
            boolean didStart = false;
            switch(softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
                case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
                    if (!isTextEditor || !doAutoShow) {
                        if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
                            // soft input window if it is shown.
                            if (DEBUG)
                                Slog.v(TAG, "Unspecified window will hide input");
                            hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
                        }
                    } else if (isTextEditor && doAutoShow && (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
                        // is more room for the target window + IME.
                        if (DEBUG)
                            Slog.v(TAG, "Unspecified window will show input");
                        if (attribute != null) {
                            res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute, controlFlags);
                            didStart = true;
                        }
                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
                    }
                    break;
                case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
                    // Do nothing.
                    break;
                case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
                    if ((softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
                        if (DEBUG)
                            Slog.v(TAG, "Window asks to hide input going forward");
                        hideCurrentInputLocked(0, null);
                    }
                    break;
                case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
                    if (DEBUG)
                        Slog.v(TAG, "Window asks to hide input");
                    hideCurrentInputLocked(0, null);
                    break;
                case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
                    if ((softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
                        if (DEBUG)
                            Slog.v(TAG, "Window asks to show input going forward");
                        if (attribute != null) {
                            res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute, controlFlags);
                            didStart = true;
                        }
                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
                    }
                    break;
                case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
                    if (DEBUG)
                        Slog.v(TAG, "Window asks to always show input");
                    if (attribute != null) {
                        res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute, controlFlags);
                        didStart = true;
                    }
                    showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
                    break;
            }
            if (!didStart && attribute != null) {
                res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute, controlFlags);
            }
        }
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
    return res;
}
Also used : InputBindResult(com.android.internal.view.InputBindResult) RemoteException(android.os.RemoteException)

Example 15 with InputBindResult

use of com.android.internal.view.InputBindResult in project android_frameworks_base by crdroidandroid.

the class InputMethodManagerService method onSessionCreated.

void onSessionCreated(IInputMethod method, IInputMethodSession session, InputChannel channel) {
    synchronized (mMethodMap) {
        if (mCurMethod != null && method != null && mCurMethod.asBinder() == method.asBinder()) {
            if (mCurClient != null) {
                clearClientSessionLocked(mCurClient);
                mCurClient.curSession = new SessionState(mCurClient, method, session, channel);
                InputBindResult res = attachNewInputLocked(true);
                if (res.method != null) {
                    executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(MSG_BIND_CLIENT, mCurClient.client, res));
                }
                return;
            }
        }
    }
    // Session abandoned.  Close its associated input channel.
    channel.dispose();
}
Also used : InputBindResult(com.android.internal.view.InputBindResult)

Aggregations

InputBindResult (com.android.internal.view.InputBindResult)37 RemoteException (android.os.RemoteException)25 Handler (android.os.Handler)7 View (android.view.View)7 PendingIntent (android.app.PendingIntent)6 Intent (android.content.Intent)6 Binder (android.os.Binder)6 IBinder (android.os.IBinder)6 InputChannel (android.view.InputChannel)6 InputMethodInfo (android.view.inputmethod.InputMethodInfo)6 SomeArgs (com.android.internal.os.SomeArgs)6 IInputContext (com.android.internal.view.IInputContext)6 IInputMethod (com.android.internal.view.IInputMethod)6 IInputMethodClient (com.android.internal.view.IInputMethodClient)6 IInputSessionCallback (com.android.internal.view.IInputSessionCallback)6 EditorInfo (android.view.inputmethod.EditorInfo)5