All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.android.internal.view.InputConnectionWrapper Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 14-robolectric-10818077
Show newest version
/*
 * Copyright (C) 2008 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 com.android.internal.view;

import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;

public class InputConnectionWrapper implements InputConnection {
    private static final int MAX_WAIT_TIME_MILLIS = 2000;
    private final IInputContext mIInputContext;
    
    static class InputContextCallback extends IInputContextCallback.Stub {
        private static final String TAG = "InputConnectionWrapper.ICC";
        public int mSeq;
        public boolean mHaveValue;
        public CharSequence mTextBeforeCursor;
        public CharSequence mTextAfterCursor;
        public CharSequence mSelectedText;
        public ExtractedText mExtractedText;
        public int mCursorCapsMode;
        public boolean mRequestUpdateCursorAnchorInfoResult;
        
        // A 'pool' of one InputContextCallback.  Each ICW request will attempt to gain
        // exclusive access to this object.
        private static InputContextCallback sInstance = new InputContextCallback();
        private static int sSequenceNumber = 1;
        
        /**
         * Returns an InputContextCallback object that is guaranteed not to be in use by
         * any other thread.  The returned object's 'have value' flag is cleared and its expected
         * sequence number is set to a new integer.  We use a sequence number so that replies that
         * occur after a timeout has expired are not interpreted as replies to a later request.
         */
        private static InputContextCallback getInstance() {
            synchronized (InputContextCallback.class) {
                // Return sInstance if it's non-null, otherwise construct a new callback
                InputContextCallback callback;
                if (sInstance != null) {
                    callback = sInstance;
                    sInstance = null;
                    
                    // Reset the callback
                    callback.mHaveValue = false;
                } else {
                    callback = new InputContextCallback();
                }
                
                // Set the sequence number
                callback.mSeq = sSequenceNumber++;
                return callback;
            }
        }
        
        /**
         * Makes the given InputContextCallback available for use in the future.
         */
        private void dispose() {
            synchronized (InputContextCallback.class) {
                // If sInstance is non-null, just let this object be garbage-collected
                if (sInstance == null) {
                    // Allow any objects being held to be gc'ed
                    mTextAfterCursor = null;
                    mTextBeforeCursor = null;
                    mExtractedText = null;
                    sInstance = this;
                }
            }
        }
        
        public void setTextBeforeCursor(CharSequence textBeforeCursor, int seq) {
            synchronized (this) {
                if (seq == mSeq) {
                    mTextBeforeCursor = textBeforeCursor;
                    mHaveValue = true;
                    notifyAll();
                } else {
                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
                            + ") in setTextBeforeCursor, ignoring.");
                }
            }
        }

        public void setTextAfterCursor(CharSequence textAfterCursor, int seq) {
            synchronized (this) {
                if (seq == mSeq) {
                    mTextAfterCursor = textAfterCursor;
                    mHaveValue = true;
                    notifyAll();
                } else {
                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
                            + ") in setTextAfterCursor, ignoring.");
                }
            }
        }

        public void setSelectedText(CharSequence selectedText, int seq) {
            synchronized (this) {
                if (seq == mSeq) {
                    mSelectedText = selectedText;
                    mHaveValue = true;
                    notifyAll();
                } else {
                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
                            + ") in setSelectedText, ignoring.");
                }
            }
        }

        public void setCursorCapsMode(int capsMode, int seq) {
            synchronized (this) {
                if (seq == mSeq) {
                    mCursorCapsMode = capsMode; 
                    mHaveValue = true;  
                    notifyAll();
                } else {
                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
                            + ") in setCursorCapsMode, ignoring.");
                }
            }
        }

        public void setExtractedText(ExtractedText extractedText, int seq) {
            synchronized (this) {
                if (seq == mSeq) {
                    mExtractedText = extractedText;
                    mHaveValue = true;
                    notifyAll();
                } else {
                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
                            + ") in setExtractedText, ignoring.");
                }
            }
        }

        public void setRequestUpdateCursorAnchorInfoResult(boolean result, int seq) {
            synchronized (this) {
                if (seq == mSeq) {
                    mRequestUpdateCursorAnchorInfoResult = result;
                    mHaveValue = true;
                    notifyAll();
                } else {
                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
                            + ") in setCursorAnchorInfoRequestResult, ignoring.");
                }
            }
        }

        /**
         * Waits for a result for up to {@link #MAX_WAIT_TIME_MILLIS} milliseconds.
         * 
         * 

The caller must be synchronized on this callback object. */ void waitForResultLocked() { long startTime = SystemClock.uptimeMillis(); long endTime = startTime + MAX_WAIT_TIME_MILLIS; while (!mHaveValue) { long remainingTime = endTime - SystemClock.uptimeMillis(); if (remainingTime <= 0) { Log.w(TAG, "Timed out waiting on IInputContextCallback"); return; } try { wait(remainingTime); } catch (InterruptedException e) { } } } } public InputConnectionWrapper(IInputContext inputContext) { mIInputContext = inputContext; } public CharSequence getTextAfterCursor(int length, int flags) { CharSequence value = null; try { InputContextCallback callback = InputContextCallback.getInstance(); mIInputContext.getTextAfterCursor(length, flags, callback.mSeq, callback); synchronized (callback) { callback.waitForResultLocked(); if (callback.mHaveValue) { value = callback.mTextAfterCursor; } } callback.dispose(); } catch (RemoteException e) { return null; } return value; } public CharSequence getTextBeforeCursor(int length, int flags) { CharSequence value = null; try { InputContextCallback callback = InputContextCallback.getInstance(); mIInputContext.getTextBeforeCursor(length, flags, callback.mSeq, callback); synchronized (callback) { callback.waitForResultLocked(); if (callback.mHaveValue) { value = callback.mTextBeforeCursor; } } callback.dispose(); } catch (RemoteException e) { return null; } return value; } public CharSequence getSelectedText(int flags) { CharSequence value = null; try { InputContextCallback callback = InputContextCallback.getInstance(); mIInputContext.getSelectedText(flags, callback.mSeq, callback); synchronized (callback) { callback.waitForResultLocked(); if (callback.mHaveValue) { value = callback.mSelectedText; } } callback.dispose(); } catch (RemoteException e) { return null; } return value; } public int getCursorCapsMode(int reqModes) { int value = 0; try { InputContextCallback callback = InputContextCallback.getInstance(); mIInputContext.getCursorCapsMode(reqModes, callback.mSeq, callback); synchronized (callback) { callback.waitForResultLocked(); if (callback.mHaveValue) { value = callback.mCursorCapsMode; } } callback.dispose(); } catch (RemoteException e) { return 0; } return value; } public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { ExtractedText value = null; try { InputContextCallback callback = InputContextCallback.getInstance(); mIInputContext.getExtractedText(request, flags, callback.mSeq, callback); synchronized (callback) { callback.waitForResultLocked(); if (callback.mHaveValue) { value = callback.mExtractedText; } } callback.dispose(); } catch (RemoteException e) { return null; } return value; } public boolean commitText(CharSequence text, int newCursorPosition) { try { mIInputContext.commitText(text, newCursorPosition); return true; } catch (RemoteException e) { return false; } } public boolean commitCompletion(CompletionInfo text) { try { mIInputContext.commitCompletion(text); return true; } catch (RemoteException e) { return false; } } public boolean commitCorrection(CorrectionInfo correctionInfo) { try { mIInputContext.commitCorrection(correctionInfo); return true; } catch (RemoteException e) { return false; } } public boolean setSelection(int start, int end) { try { mIInputContext.setSelection(start, end); return true; } catch (RemoteException e) { return false; } } public boolean performEditorAction(int actionCode) { try { mIInputContext.performEditorAction(actionCode); return true; } catch (RemoteException e) { return false; } } public boolean performContextMenuAction(int id) { try { mIInputContext.performContextMenuAction(id); return true; } catch (RemoteException e) { return false; } } public boolean setComposingRegion(int start, int end) { try { mIInputContext.setComposingRegion(start, end); return true; } catch (RemoteException e) { return false; } } public boolean setComposingText(CharSequence text, int newCursorPosition) { try { mIInputContext.setComposingText(text, newCursorPosition); return true; } catch (RemoteException e) { return false; } } public boolean finishComposingText() { try { mIInputContext.finishComposingText(); return true; } catch (RemoteException e) { return false; } } public boolean beginBatchEdit() { try { mIInputContext.beginBatchEdit(); return true; } catch (RemoteException e) { return false; } } public boolean endBatchEdit() { try { mIInputContext.endBatchEdit(); return true; } catch (RemoteException e) { return false; } } public boolean sendKeyEvent(KeyEvent event) { try { mIInputContext.sendKeyEvent(event); return true; } catch (RemoteException e) { return false; } } public boolean clearMetaKeyStates(int states) { try { mIInputContext.clearMetaKeyStates(states); return true; } catch (RemoteException e) { return false; } } public boolean deleteSurroundingText(int beforeLength, int afterLength) { try { mIInputContext.deleteSurroundingText(beforeLength, afterLength); return true; } catch (RemoteException e) { return false; } } public boolean reportFullscreenMode(boolean enabled) { try { mIInputContext.reportFullscreenMode(enabled); return true; } catch (RemoteException e) { return false; } } public boolean performPrivateCommand(String action, Bundle data) { try { mIInputContext.performPrivateCommand(action, data); return true; } catch (RemoteException e) { return false; } } public boolean requestCursorUpdates(int cursorUpdateMode) { boolean result = false; try { InputContextCallback callback = InputContextCallback.getInstance(); mIInputContext.requestUpdateCursorAnchorInfo(cursorUpdateMode, callback.mSeq, callback); synchronized (callback) { callback.waitForResultLocked(); if (callback.mHaveValue) { result = callback.mRequestUpdateCursorAnchorInfoResult; } } callback.dispose(); } catch (RemoteException e) { return false; } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy