示例#1
0
 @Override
 public boolean setInputConnectionHandler(Handler handler) {
   if (handler == mIcPostHandler) {
     return true;
   }
   if (!mFocused) {
     return false;
   }
   if (DEBUG) {
     assertOnIcThread();
   }
   // There are three threads at this point: Gecko thread, old IC thread, and new IC
   // thread, and we want to safely switch from old IC thread to new IC thread.
   // We first send a TYPE_SET_HANDLER action to the Gecko thread; this ensures that
   // the Gecko thread is stopped at a known point. At the same time, the old IC
   // thread blocks on the action; this ensures that the old IC thread is stopped at
   // a known point. Finally, inside the Gecko thread, we post a Runnable to the old
   // IC thread; this Runnable switches from old IC thread to new IC thread. We
   // switch IC thread on the old IC thread to ensure any pending Runnables on the
   // old IC thread are processed before we switch over. Inside the Gecko thread, we
   // also post a Runnable to the new IC thread; this Runnable blocks until the
   // switch is complete; this ensures that the new IC thread won't accept
   // InputConnection calls until after the switch.
   mActionQueue.offer(Action.newSetHandler(handler));
   mActionQueue.syncWithGecko();
   return true;
 }
示例#2
0
 @Override
 public void setSpan(Object what, int start, int end, int flags) {
   if (what == Selection.SELECTION_START) {
     if ((flags & Spanned.SPAN_INTERMEDIATE) != 0) {
       // We will get the end offset next, just save the start for now
       mSavedSelectionStart = start;
     } else {
       mActionQueue.offer(Action.newSetSelection(start, -1));
     }
   } else if (what == Selection.SELECTION_END) {
     mActionQueue.offer(Action.newSetSelection(mSavedSelectionStart, end));
     mSavedSelectionStart = -1;
   } else {
     mActionQueue.offer(Action.newSetSpan(what, start, end, flags));
   }
 }
示例#3
0
  @Override
  public Editable replace(int st, int en, CharSequence source, int start, int end) {

    CharSequence text = source;
    if (start < 0 || start > end || end > text.length()) {
      Log.e(
          LOGTAG,
          "invalid replace offsets: " + start + " to " + end + ", length: " + text.length());
      throw new IllegalArgumentException("invalid replace offsets");
    }
    if (start != 0 || end != text.length()) {
      text = text.subSequence(start, end);
    }
    if (mFilters != null) {
      // Filter text before sending the request to Gecko
      for (int i = 0; i < mFilters.length; ++i) {
        final CharSequence cs = mFilters[i].filter(text, 0, text.length(), mProxy, st, en);
        if (cs != null) {
          text = cs;
        }
      }
    }
    if (text == source) {
      // Always create a copy
      text = new SpannableString(source);
    }
    mActionQueue.offer(Action.newReplaceText(text, Math.min(st, en), Math.max(st, en)));
    return mProxy;
  }
示例#4
0
 @Override
 public void removeSpan(Object what) {
   if (what == Selection.SELECTION_START || what == Selection.SELECTION_END) {
     Log.w(LOGTAG, "selection removed with removeSpan()");
   }
   mActionQueue.offer(Action.newRemoveSpan(what));
 }
示例#5
0
 @Override
 public void sendKeyEvent(final KeyEvent event, int action, int metaState) {
   if (DEBUG) {
     assertOnIcThread();
     Log.d(LOGTAG, "sendKeyEvent(" + event + ", " + action + ", " + metaState + ")");
   }
   /*
      We are actually sending two events to Gecko here,
      1. Event from the event parameter (key event)
      2. Sync event from the mActionQueue.offer call
      The first event is a normal event that does not reply back to us,
      the second sync event will have a reply, during which we see that there is a pending
      event-type action, and update the selection/composition/etc. accordingly.
   */
   onKeyEvent(event, action, metaState, /* isSynthesizedImeKey */ false);
   mActionQueue.offer(new Action(Action.TYPE_EVENT));
 }