diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-19 10:57:31 -0800 | 
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-19 10:57:31 -0800 | 
| commit | 3001a035439d8134a7d70d796376d1dfbff3cdcd (patch) | |
| tree | 343ccdba15a594ff6e50c874a145232753315a30 /core/java/android/inputmethodservice | |
| parent | da996f390e17e16f2dfa60e972e7ebc4f868f37e (diff) | |
| download | frameworks_base-3001a035439d8134a7d70d796376d1dfbff3cdcd.zip frameworks_base-3001a035439d8134a7d70d796376d1dfbff3cdcd.tar.gz frameworks_base-3001a035439d8134a7d70d796376d1dfbff3cdcd.tar.bz2 | |
auto import from //branches/cupcake/...@132276
Diffstat (limited to 'core/java/android/inputmethodservice')
4 files changed, 194 insertions, 98 deletions
| diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java index d9f10a9..52f8209 100644 --- a/core/java/android/inputmethodservice/ExtractEditText.java +++ b/core/java/android/inputmethodservice/ExtractEditText.java @@ -102,7 +102,7 @@ public class ExtractEditText extends EditText {       * highlight and cursor will be displayed.       */      @Override public boolean hasWindowFocus() { -        return true; +        return this.isEnabled() ? true : false;      }      /** @@ -110,7 +110,7 @@ public class ExtractEditText extends EditText {       * highlight and cursor will be displayed.       */      @Override public boolean isFocused() { -        return true; +        return this.isEnabled() ? true : false;      }      /** @@ -118,7 +118,6 @@ public class ExtractEditText extends EditText {       * highlight and cursor will be displayed.       */      @Override public boolean hasFocus() { -        return true; +        return this.isEnabled() ? true : false;      } -      } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index c884120..4be1fc7 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -229,9 +229,11 @@ public class InputMethodService extends AbstractInputMethodService {      InputConnection mStartedInputConnection;      EditorInfo mInputEditorInfo; +    int mShowInputFlags;      boolean mShowInputRequested;      boolean mLastShowInputRequested;      int mCandidatesVisibility; +    CompletionInfo[] mCurCompletions;      boolean mShowInputForced; @@ -328,6 +330,7 @@ public class InputMethodService extends AbstractInputMethodService {           */          public void hideSoftInput() {              if (DEBUG) Log.v(TAG, "hideSoftInput()"); +            mShowInputFlags = 0;              mShowInputRequested = false;              mShowInputForced = false;              hideWindow(); @@ -338,7 +341,10 @@ public class InputMethodService extends AbstractInputMethodService {           */          public void showSoftInput(int flags) {              if (DEBUG) Log.v(TAG, "showSoftInput()"); -            onShowRequested(flags); +            mShowInputFlags = 0; +            if (onShowInputRequested(flags, false)) { +                showWindow(true); +            }          }      } @@ -364,6 +370,7 @@ public class InputMethodService extends AbstractInputMethodService {              if (!isEnabled()) {                  return;              } +            mCurCompletions = completions;              onDisplayCompletions(completions);          } @@ -557,8 +564,9 @@ public class InputMethodService extends AbstractInputMethodService {          super.onConfigurationChanged(newConfig);          boolean visible = mWindowVisible; +        int showFlags = mShowInputFlags;          boolean showingInput = mShowInputRequested; -        boolean showingForced = mShowInputForced; +        CompletionInfo[] completions = mCurCompletions;          initViews();          mInputViewStarted = false;          mCandidatesViewStarted = false; @@ -567,19 +575,24 @@ public class InputMethodService extends AbstractInputMethodService {                      getCurrentInputEditorInfo(), true);          }          if (visible) { -            if (showingForced) { -                // If we are showing the full soft keyboard, then go through -                // this path to take care of current decisions about fullscreen -                // etc. -                onShowRequested(InputMethod.SHOW_FORCED|InputMethod.SHOW_EXPLICIT); -            } else if (showingInput) { -                // If we are showing the full soft keyboard, then go through -                // this path to take care of current decisions about fullscreen -                // etc. -                onShowRequested(InputMethod.SHOW_EXPLICIT); -            } else { -                // Otherwise just put it back for its candidates. +            if (showingInput) { +                // If we were last showing the soft keyboard, try to do so again. +                if (onShowInputRequested(showFlags, true)) { +                    showWindow(true); +                    if (completions != null) { +                        mCurCompletions = completions; +                        onDisplayCompletions(completions); +                    } +                } else { +                    hideWindow(); +                } +            } else if (mCandidatesVisibility == View.VISIBLE) { +                // If the candidates are currently visible, make sure the +                // window is shown for them.                  showWindow(false); +            } else { +                // Otherwise hide the window. +                hideWindow();              }          }      } @@ -1065,36 +1078,42 @@ public class InputMethodService extends AbstractInputMethodService {       * The system has decided that it may be time to show your input method.       * This is called due to a corresponding call to your       * {@link InputMethod#showSoftInput(int) InputMethod.showSoftInput(int)} -     * method.  The default implementation simply calls -     * {@link #showWindow(boolean)}, except if the -     * {@link InputMethod#SHOW_EXPLICIT InputMethod.SHOW_EXPLICIT} flag is -     * not set and the input method is running in fullscreen mode. +     * method.  The default implementation uses +     * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()}, +     * and the current configuration to decide whether the input view should +     * be shown at this point.       *        * @param flags Provides additional information about the show request,       * as per {@link InputMethod#showSoftInput(int) InputMethod.showSoftInput(int)}. +     * @param configChange This is true if we are re-showing due to a +     * configuration change. +     * @return Returns true to indicate that the window should be shown.       */ -    public void onShowRequested(int flags) { +    public boolean onShowInputRequested(int flags, boolean configChange) {          if (!onEvaluateInputViewShown()) { -            return; +            return false;          }          if ((flags&InputMethod.SHOW_EXPLICIT) == 0) { -            if (onEvaluateFullscreenMode()) { +            if (!configChange && onEvaluateFullscreenMode()) {                  // Don't show if this is not explicitly requested by the user and                  // the input method is fullscreen.  That would be too disruptive. -                return; +                // However, we skip this change for a config change, since if +                // the IME is already shown we do want to go into fullscreen +                // mode at this point. +                return false;              }              Configuration config = getResources().getConfiguration();              if (config.keyboard != Configuration.KEYBOARD_NOKEYS) {                  // And if the device has a hard keyboard, even if it is                  // currently hidden, don't show the input method implicitly.                  // These kinds of devices don't need it that much. -                return; +                return false;              }          }          if ((flags&InputMethod.SHOW_FORCED) != 0) {              mShowInputForced = true;          } -        showWindow(true); +        return true;      }      public void showWindow(boolean showInput) { @@ -1106,7 +1125,6 @@ public class InputMethodService extends AbstractInputMethodService {                  + " mInputStarted=" + mInputStarted);          boolean doShowInput = false;          boolean wasVisible = mWindowVisible; -        boolean wasCreated = mWindowCreated;          mWindowVisible = true;          if (!mShowInputRequested) {              if (mInputStarted) { @@ -1240,6 +1258,7 @@ public class InputMethodService extends AbstractInputMethodService {          }          mInputStarted = false;          mStartedInputConnection = null; +        mCurCompletions = null;      }      void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) { @@ -1550,7 +1569,11 @@ public class InputMethodService extends AbstractInputMethodService {                  eet.setInputType(inputType);                  eet.setHint(mInputEditorInfo.hintText);                  if (mExtractedText != null) { +                    eet.setEnabled(true);                      eet.setExtractedText(mExtractedText); +                } else { +                    eet.setEnabled(false); +                    eet.setText("");                  }              } finally {                  eet.finishInternalChanges(); @@ -1586,7 +1609,8 @@ public class InputMethodService extends AbstractInputMethodService {          p.println("  mShowInputRequested=" + mShowInputRequested                  + " mLastShowInputRequested=" + mLastShowInputRequested -                + " mShowInputForced=" + mShowInputForced); +                + " mShowInputForced=" + mShowInputForced +                + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));          p.println("  mCandidatesVisibility=" + mCandidatesVisibility                  + " mFullscreenApplied=" + mFullscreenApplied                  + " mIsFullscreen=" + mIsFullscreen); diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java index 228acbe..6a560ce 100755 --- a/core/java/android/inputmethodservice/Keyboard.java +++ b/core/java/android/inputmethodservice/Keyboard.java @@ -132,7 +132,19 @@ public class Keyboard {      /** Keyboard mode, or zero, if none.  */      private int mKeyboardMode; + +    // Variables for pre-computing nearest keys. +    private static final int GRID_WIDTH = 10; +    private static final int GRID_HEIGHT = 5; +    private static final int GRID_SIZE = GRID_WIDTH * GRID_HEIGHT; +    private int mCellWidth; +    private int mCellHeight; +    private int[][] mGridNeighbors; +    private int mProximityThreshold; +    /** Number of key widths from current touch point to search for nearest keys. */ +    private static float SEARCH_DISTANCE = 1.4f; +      /**       * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.        * Some of the key size defaults can be overridden per row from what the {@link Keyboard} @@ -637,6 +649,52 @@ public class Keyboard {      public int getShiftKeyIndex() {          return mShiftKeyIndex;      } +     +    private void computeNearestNeighbors() { +        // Round-up so we don't have any pixels outside the grid +        mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH; +        mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT; +        mGridNeighbors = new int[GRID_SIZE][]; +        int[] indices = new int[mKeys.size()]; +        final int gridWidth = GRID_WIDTH * mCellWidth; +        final int gridHeight = GRID_HEIGHT * mCellHeight; +        for (int x = 0; x < gridWidth; x += mCellWidth) { +            for (int y = 0; y < gridHeight; y += mCellHeight) { +                int count = 0; +                for (int i = 0; i < mKeys.size(); i++) { +                    final Key key = mKeys.get(i); +                    if (key.squaredDistanceFrom(x, y) < mProximityThreshold || +                            key.squaredDistanceFrom(x + mCellWidth - 1, y) < mProximityThreshold || +                            key.squaredDistanceFrom(x + mCellWidth - 1, y + mCellHeight - 1)  +                                < mProximityThreshold || +                            key.squaredDistanceFrom(x, y + mCellHeight - 1) < mProximityThreshold) { +                        indices[count++] = i; +                    } +                } +                int [] cell = new int[count]; +                System.arraycopy(indices, 0, cell, 0, count); +                mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell; +            } +        } +    } +     +    /** +     * Returns the indices of the keys that are closest to the given point. +     * @param x the x-coordinate of the point +     * @param y the y-coordinate of the point +     * @return the array of integer indices for the nearest keys to the given point. If the given +     * point is out of range, then an array of size zero is returned. +     */ +    public int[] getNearestKeys(int x, int y) { +        if (mGridNeighbors == null) computeNearestNeighbors(); +        if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) { +            int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth); +            if (index < GRID_SIZE) { +                return mGridNeighbors[index]; +            } +        } +        return new int[0]; +    }      protected Row createRowFromXml(Resources res, XmlResourceParser parser) {          return new Row(res, this, parser); @@ -738,6 +796,8 @@ public class Keyboard {          mDefaultVerticalGap = getDimensionOrFraction(a,                  com.android.internal.R.styleable.Keyboard_verticalGap,                  mDisplayHeight, 0); +        mProximityThreshold = (int) (mDefaultWidth * SEARCH_DISTANCE); +        mProximityThreshold = mProximityThreshold * mProximityThreshold; // Square it for comparison          a.recycle();      } diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index b8bd10d..886e688 100755 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -159,6 +159,9 @@ public class KeyboardView extends View implements View.OnClickListener {      private static final int MSG_REPEAT = 3;      private static final int MSG_LONGPRESS = 4; +    private static final int DELAY_BEFORE_PREVIEW = 70; +    private static final int DELAY_AFTER_PREVIEW = 60; +          private int mVerticalCorrection;      private int mProximityThreshold; @@ -219,7 +222,7 @@ public class KeyboardView extends View implements View.OnClickListener {          public void handleMessage(Message msg) {              switch (msg.what) {                  case MSG_SHOW_PREVIEW: -                    mPreviewText.setVisibility(VISIBLE); +                    showKey(msg.arg1);                      break;                  case MSG_REMOVE_PREVIEW:                      mPreviewText.setVisibility(INVISIBLE); @@ -234,7 +237,6 @@ public class KeyboardView extends View implements View.OnClickListener {                      openPopupIfRequired((MotionEvent) msg.obj);                      break;              } -                      }      }; @@ -533,10 +535,10 @@ public class KeyboardView extends View implements View.OnClickListener {              dimensionSum += Math.min(key.width, key.height) + key.gap;          }          if (dimensionSum < 0 || length == 0) return; -        mProximityThreshold = (int) (dimensionSum * 1.5f / length); +        mProximityThreshold = (int) (dimensionSum * 1.4f / length);          mProximityThreshold *= mProximityThreshold; // Square it      } -     +      @Override      public void onDraw(Canvas canvas) {          super.onDraw(canvas); @@ -647,9 +649,10 @@ public class KeyboardView extends View implements View.OnClickListener {          int closestKey = NOT_A_KEY;          int closestKeyDist = mProximityThreshold + 1;          java.util.Arrays.fill(mDistances, Integer.MAX_VALUE); -        final int keyCount = keys.length; +        int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); +        final int keyCount = nearestKeyIndices.length;          for (int i = 0; i < keyCount; i++) { -            final Key key = keys[i]; +            final Key key = keys[nearestKeyIndices[i]];              int dist = 0;              boolean isInside = key.isInside(x,y);              if (((mProximityCorrectOn  @@ -660,7 +663,7 @@ public class KeyboardView extends View implements View.OnClickListener {                  final int nCodes = key.codes.length;                  if (dist < closestKeyDist) {                      closestKeyDist = dist; -                    closestKey = i; +                    closestKey = nearestKeyIndices[i];                  }                  if (allKeys == null) continue; @@ -674,9 +677,6 @@ public class KeyboardView extends View implements View.OnClickListener {                                  allKeys.length - j - nCodes);                          for (int c = 0; c < nCodes; c++) {                              allKeys[j + c] = key.codes[c]; -                            if (shifted) { -                                //allKeys[j + c] = Character.toUpperCase(key.codes[c]); -                            }                              mDistances[j + c] = dist;                          }                          break; @@ -685,7 +685,7 @@ public class KeyboardView extends View implements View.OnClickListener {              }              if (isInside) { -                primaryIndex = i; +                primaryIndex = nearestKeyIndices[i];              }          }          if (primaryIndex == NOT_A_KEY) { @@ -696,7 +696,7 @@ public class KeyboardView extends View implements View.OnClickListener {      private void detectAndSendKey(int x, int y, long eventTime) {          int index = mCurrentKey; -        if (index != NOT_A_KEY) { +        if (index != NOT_A_KEY && index < mKeys.length) {              final Key key = mKeys[index];              if (key.text != null) {                  for (int i = 0; i < key.text.length(); i++) { @@ -763,70 +763,83 @@ public class KeyboardView extends View implements View.OnClickListener {              if (previewPopup.isShowing()) {                  if (keyIndex == NOT_A_KEY) {                      mHandler.sendMessageDelayed(mHandler -                            .obtainMessage(MSG_REMOVE_PREVIEW), 60); +                            .obtainMessage(MSG_REMOVE_PREVIEW),  +                            DELAY_AFTER_PREVIEW);                  }              }              if (keyIndex != NOT_A_KEY) { -                Key key = keys[keyIndex]; -                if (key.icon != null) { -                    mPreviewText.setCompoundDrawables(null, null, null,  -                            key.iconPreview != null ? key.iconPreview : key.icon); -                    mPreviewText.setText(null); -                } else { -                    mPreviewText.setCompoundDrawables(null, null, null, null); -                    mPreviewText.setText(getPreviewText(key)); -                    if (key.label.length() > 1 && key.codes.length < 2) { -                        mPreviewText.setTextSize(mLabelTextSize); -                        mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); -                    } else { -                        mPreviewText.setTextSize(mPreviewTextSizeLarge); -                        mPreviewText.setTypeface(Typeface.DEFAULT); -                    } -                } -                mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),  -                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); -                int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width  -                        + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); -                final int popupHeight = mPreviewHeight; -                LayoutParams lp = mPreviewText.getLayoutParams(); -                if (lp != null) { -                    lp.width = popupWidth; -                    lp.height = popupHeight; -                } -                if (!mPreviewCentered) { -                    mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft; -                    mPopupPreviewY = key.y - popupHeight + mPreviewOffset; -                } else { -                    // TODO: Fix this if centering is brought back -                    mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2; -                    mPopupPreviewY = - mPreviewText.getMeasuredHeight(); -                } -                mHandler.removeMessages(MSG_REMOVE_PREVIEW); -                if (mOffsetInWindow == null) { -                    mOffsetInWindow = new int[2]; -                    getLocationInWindow(mOffsetInWindow); -                    mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero -                    mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero -                } -                // Set the preview background state -                mPreviewText.getBackground().setState( -                        key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); -                if (previewPopup.isShowing()) { -                    previewPopup.update(mPopupPreviewX + mOffsetInWindow[0], -                            mPopupPreviewY + mOffsetInWindow[1],  -                            popupWidth, popupHeight); +                if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { +                    // Show right away, if it's already visible and finger is moving around +                    showKey(keyIndex);                  } else { -                    previewPopup.setWidth(popupWidth); -                    previewPopup.setHeight(popupHeight); -                    previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY,  -                            mPopupPreviewX + mOffsetInWindow[0],  -                            mPopupPreviewY + mOffsetInWindow[1]); +                    mHandler.sendMessageDelayed( +                            mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0),  +                            DELAY_BEFORE_PREVIEW);                  } -                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0), -                        ViewConfiguration.getTapTimeout());              }          }      } +     +    private void showKey(final int keyIndex) { +        final PopupWindow previewPopup = mPreviewPopup; +        final Key[] keys = mKeys; +        Key key = keys[keyIndex]; +        if (key.icon != null) { +            mPreviewText.setCompoundDrawables(null, null, null,  +                    key.iconPreview != null ? key.iconPreview : key.icon); +            mPreviewText.setText(null); +        } else { +            mPreviewText.setCompoundDrawables(null, null, null, null); +            mPreviewText.setText(getPreviewText(key)); +            if (key.label.length() > 1 && key.codes.length < 2) { +                mPreviewText.setTextSize(mLabelTextSize); +                mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); +            } else { +                mPreviewText.setTextSize(mPreviewTextSizeLarge); +                mPreviewText.setTypeface(Typeface.DEFAULT); +            } +        } +        mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),  +                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); +        int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width  +                + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); +        final int popupHeight = mPreviewHeight; +        LayoutParams lp = mPreviewText.getLayoutParams(); +        if (lp != null) { +            lp.width = popupWidth; +            lp.height = popupHeight; +        } +        if (!mPreviewCentered) { +            mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft; +            mPopupPreviewY = key.y - popupHeight + mPreviewOffset; +        } else { +            // TODO: Fix this if centering is brought back +            mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2; +            mPopupPreviewY = - mPreviewText.getMeasuredHeight(); +        } +        mHandler.removeMessages(MSG_REMOVE_PREVIEW); +        if (mOffsetInWindow == null) { +            mOffsetInWindow = new int[2]; +            getLocationInWindow(mOffsetInWindow); +            mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero +            mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero +        } +        // Set the preview background state +        mPreviewText.getBackground().setState( +                key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); +        if (previewPopup.isShowing()) { +            previewPopup.update(mPopupPreviewX + mOffsetInWindow[0], +                    mPopupPreviewY + mOffsetInWindow[1],  +                    popupWidth, popupHeight); +        } else { +            previewPopup.setWidth(popupWidth); +            previewPopup.setHeight(popupHeight); +            previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY,  +                    mPopupPreviewX + mOffsetInWindow[0],  +                    mPopupPreviewY + mOffsetInWindow[1]); +        } +        mPreviewText.setVisibility(VISIBLE); +    }      private void invalidateKey(int keyIndex) {          if (keyIndex < 0 || keyIndex >= mKeys.length) { | 
