private boolean processKey(int keyCode, KeyEvent event, boolean down) {
    if (GamepadUtils.isSonyXperiaGamepadKeyEvent(event)) {
      event = GamepadUtils.translateSonyXperiaGamepadKeys(keyCode, event);
      keyCode = event.getKeyCode();
    }

    if (keyCode > KeyEvent.getMaxKeyCode() || !shouldProcessKey(keyCode, event)) {
      return false;
    }
    event = translateKey(keyCode, event);
    keyCode = event.getKeyCode();

    View view = getView();
    if (view == null) {
      InputThreadUtils.sInstance.sendEventFromUiThread(
          ThreadUtils.getUiHandler(), mEditableClient, GoannaEvent.createKeyEvent(event, 0));
      return true;
    }

    // KeyListener returns true if it handled the event for us. KeyListener is only
    // safe to use on the UI thread; therefore we need to pass a proxy Editable to it
    KeyListener keyListener = TextKeyListener.getInstance();
    Handler uiHandler = view.getRootView().getHandler();
    Editable uiEditable =
        InputThreadUtils.sInstance.getEditableForUiThread(uiHandler, mEditableClient);
    boolean skip = shouldSkipKeyListener(keyCode, event);
    if (down) {
      mEditableClient.setSuppressKeyUp(true);
    }
    if (skip
        || (down && !keyListener.onKeyDown(view, uiEditable, keyCode, event))
        || (!down && !keyListener.onKeyUp(view, uiEditable, keyCode, event))) {
      InputThreadUtils.sInstance.sendEventFromUiThread(
          uiHandler,
          mEditableClient,
          GoannaEvent.createKeyEvent(event, TextKeyListener.getMetaState(uiEditable)));
      if (skip && down) {
        // Usually, the down key listener call above adjusts meta states for us.
        // However, if we skip that call above, we have to manually adjust meta
        // states so the meta states remain consistent
        TextKeyListener.adjustMetaAfterKeypress(uiEditable);
      }
    }
    if (down) {
      mEditableClient.setSuppressKeyUp(false);
    }
    return true;
  }
  private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) {
    if (DEBUG) {
      Log.d(
          LOGTAG,
          "IME: processKeyUp(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")");
    }

    switch (keyCode) {
      case KeyEvent.KEYCODE_BACK:
      case KeyEvent.KEYCODE_SEARCH:
      case KeyEvent.KEYCODE_MENU:
        return false;
      default:
        break;
    }

    if (isPreIme
        && mIMEState != IME_STATE_DISABLED
        && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0)
      // Let active IME process pre-IME key events
      return false;

    View view = GeckoApp.mAppContext.getLayerController().getView();
    KeyListener keyListener = TextKeyListener.getInstance();

    if (mIMEState == IME_STATE_DISABLED
        || keyCode == KeyEvent.KEYCODE_ENTER
        || keyCode == KeyEvent.KEYCODE_DEL
        || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0
        || !keyListener.onKeyUp(view, mEditable, keyCode, event)) {
      GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event));
    }

    return true;
  }
 public void handleKeyboardType(int type, boolean autocorrect) {
   // Switched the keyboard handler to use the inputType rather than the rawInputType
   // This is kinda brute-force but more effective for most use-cases
   switch (type) {
     case KEYBOARD_ASCII:
       tv.setKeyListener(TextKeyListener.getInstance(autocorrect, Capitalize.NONE));
       tv.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL);
       // tv.setRawInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL);
       break;
     case KEYBOARD_NUMBERS_PUNCTUATION:
       tv.setInputType(InputType.TYPE_CLASS_NUMBER);
       // tv.setKeyListener(DigitsKeyListener.getInstance());
       break;
     case KEYBOARD_URL:
       Log.i(LCAT, "Setting keyboard type URL-3");
       // tv.setKeyListener(TextKeyListener.getInstance(autocorrect, Capitalize.NONE));
       tv.setImeOptions(EditorInfo.IME_ACTION_GO);
       // tv.setRawInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
       tv.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
       break;
     case KEYBOARD_NUMBER_PAD:
       tv.setKeyListener(DigitsKeyListener.getInstance(true, true));
       // tv.setRawInputType(InputType.TYPE_CLASS_NUMBER);
       tv.setInputType(InputType.TYPE_CLASS_NUMBER);
       break;
     case KEYBOARD_PHONE_PAD:
       tv.setKeyListener(DialerKeyListener.getInstance());
       // tv.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_CLASS_PHONE);
       tv.setInputType(InputType.TYPE_CLASS_PHONE);
       break;
     case KEYBOARD_EMAIL_ADDRESS:
       // tv.setKeyListener(TextKeyListener.getInstance(autocorrect, Capitalize.NONE));
       tv.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
       break;
     case KEYBOARD_DEFAULT:
       tv.setKeyListener(TextKeyListener.getInstance(autocorrect, Capitalize.NONE));
       // tv.setRawInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL);
       tv.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL);
       break;
     case KEYBOARD_PASSWORD:
       tv.setKeyListener(TextKeyListener.getInstance(false, Capitalize.NONE));
       // tv.setRawInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
       tv.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
       break;
   }
 }
  private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) {
    if (DEBUG) {
      Log.d(
          LOGTAG,
          "IME: processKeyDown(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")");
    }

    clampSelection();

    switch (keyCode) {
      case KeyEvent.KEYCODE_MENU:
      case KeyEvent.KEYCODE_BACK:
      case KeyEvent.KEYCODE_VOLUME_UP:
      case KeyEvent.KEYCODE_VOLUME_DOWN:
      case KeyEvent.KEYCODE_SEARCH:
        return false;
      case KeyEvent.KEYCODE_DEL:
        // See comments in GeckoInputConnection.onKeyDel
        if (onKeyDel()) {
          return true;
        }
        break;
      case KeyEvent.KEYCODE_ENTER:
        if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0
            && mIMEActionHint.equalsIgnoreCase("next"))
          event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB);
        break;
      default:
        break;
    }

    if (isPreIme
        && mIMEState != IME_STATE_DISABLED
        && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0)
      // Let active IME process pre-IME key events
      return false;

    View view = GeckoApp.mAppContext.getLayerController().getView();
    KeyListener keyListener = TextKeyListener.getInstance();

    // KeyListener returns true if it handled the event for us.
    if (mIMEState == IME_STATE_DISABLED
        || keyCode == KeyEvent.KEYCODE_ENTER
        || keyCode == KeyEvent.KEYCODE_DEL
        || keyCode == KeyEvent.KEYCODE_TAB
        || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0
        || !keyListener.onKeyDown(view, mEditable, keyCode, event)) {
      // Make sure selection in Gecko is up-to-date
      final Editable content = getEditable();
      int a = Selection.getSelectionStart(content);
      int b = Selection.getSelectionEnd(content);
      GeckoAppShell.sendEventToGecko(
          GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, a, b - a));

      GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event));
    }
    return true;
  }
  public PasswordUnlockScreen(
      Context context,
      Configuration configuration,
      LockPatternUtils lockPatternUtils,
      KeyguardUpdateMonitor updateMonitor,
      KeyguardScreenCallback callback) {
    super(context);

    mCreationHardKeyboardHidden = configuration.hardKeyboardHidden;
    mCreationOrientation = configuration.orientation;
    mUpdateMonitor = updateMonitor;
    mCallback = callback;
    mLockPatternUtils = lockPatternUtils;

    LayoutInflater layoutInflater = LayoutInflater.from(context);
    if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) {
      layoutInflater.inflate(R.layout.keyguard_screen_password_portrait, this, true);
    } else {
      layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true);
    }
    LockScreen.setBackground(context, (ViewGroup) findViewById(R.id.root));
    mStatusViewManager =
        new KeyguardStatusViewManager(this, mUpdateMonitor, mLockPatternUtils, mCallback, true);

    final int quality = lockPatternUtils.getKeyguardStoredPasswordQuality();
    mIsAlpha =
        DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality
            || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality
            || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == quality;

    mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
    mPasswordEntry = (EditText) findViewById(R.id.passwordEntry);
    mPasswordEntry.setOnEditorActionListener(this);

    mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this, false);
    mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
    boolean imeOrDeleteButtonVisible = false;
    if (mIsAlpha) {
      // We always use the system IME for alpha keyboard, so hide lockscreen's soft keyboard
      mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
      mKeyboardView.setVisibility(View.GONE);
    } else {
      // Use lockscreen's numeric keyboard if the physical keyboard isn't showing
      mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
      mKeyboardView.setVisibility(
          mCreationHardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO
              ? View.INVISIBLE
              : View.VISIBLE);

      // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
      // not a separate view
      View pinDelete = findViewById(R.id.pinDel);
      if (pinDelete != null) {
        pinDelete.setVisibility(View.VISIBLE);
        imeOrDeleteButtonVisible = true;
        pinDelete.setOnClickListener(
            new OnClickListener() {
              @Override
              public void onClick(View v) {
                mKeyboardHelper.handleBackspace();
              }
            });
      }
    }

    mPasswordEntry.requestFocus();

    // This allows keyboards with overlapping qwerty/numeric keys to choose just numeric keys.
    if (mIsAlpha) {
      mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
      mPasswordEntry.setInputType(
          InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
      // mStatusViewManager.setHelpMessage(R.string.keyguard_password_enter_password_code,
      // KeyguardStatusViewManager.LOCK_ICON);
    } else {
      mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
      mPasswordEntry.setInputType(
          InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
      // mStatusViewManager.setHelpMessage(R.string.keyguard_password_enter_pin_code,
      // KeyguardStatusViewManager.LOCK_ICON);
    }

    // Poke the wakelock any time the text is selected or modified
    mPasswordEntry.setOnClickListener(
        new OnClickListener() {
          public void onClick(View v) {
            mCallback.pokeWakelock();
          }
        });

    mQuickUnlock =
        (Settings.System.getInt(
                mContext.getContentResolver(), Settings.System.LOCKSCREEN_QUICK_UNLOCK_CONTROL, 0)
            == 1);

    mPasswordEntry.addTextChangedListener(
        new TextWatcher() {
          public void onTextChanged(CharSequence s, int start, int before, int count) {}

          public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

          public void afterTextChanged(Editable s) {
            if (!mResuming) {
              mCallback.pokeWakelock();
            }
            if (mQuickUnlock) {
              String entry = mPasswordEntry.getText().toString();
              if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT
                  && mLockPatternUtils.checkPassword(entry)) {
                mCallback.keyguardDone(true);
                mCallback.reportSuccessfulUnlockAttempt();
                KeyStore.getInstance().password(entry);
              }
            }
          }
        });

    // If there's more than one IME, enable the IME switcher button
    View switchImeButton = findViewById(R.id.switch_ime_button);
    final InputMethodManager imm =
        (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
    if (mIsAlpha && switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(imm, false)) {
      switchImeButton.setVisibility(View.VISIBLE);
      imeOrDeleteButtonVisible = true;
      switchImeButton.setOnClickListener(
          new OnClickListener() {
            public void onClick(View v) {
              mCallback.pokeWakelock(); // Leave the screen on a bit longer
              imm.showInputMethodPicker();
            }
          });
    }

    // If no icon is visible, reset the left margin on the password field so the text is
    // still centered.
    if (!imeOrDeleteButtonVisible) {
      android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
      if (params instanceof MarginLayoutParams) {
        ((MarginLayoutParams) params).leftMargin = 0;
        mPasswordEntry.setLayoutParams(params);
      }
    }
  }
  @Override
  public void processProperties(TiDict d) {
    super.processProperties(d);

    if (d.containsKey("enabled")) {
      tv.setEnabled(d.getBoolean("enabled"));
    }
    if (d.containsKey("value")) {
      tv.setText(d.getString("value"));
    }
    if (d.containsKey("color")) {
      tv.setTextColor(TiConvert.toColor(d, "color"));
    }
    if (d.containsKey("hintText")) {
      tv.setHint(d.getString("hintText"));
    }
    if (d.containsKey("font")) {
      TiUIHelper.styleText(tv, d.getTiDict("font"));
    }
    if (d.containsKey("textAlign") || d.containsKey("verticalAlign")) {
      String textAlign = null;
      String verticalAlign = null;
      if (d.containsKey("textAlign")) {
        textAlign = d.getString("textAlign");
      }
      if (d.containsKey("verticalAlign")) {
        verticalAlign = d.getString("verticalAlign");
      }
      handleTextAlign(textAlign, verticalAlign);
    }
    if (d.containsKey("returnKeyType")) {
      handleReturnKeyType(d.getInt("returnKeyType"));
    }
    if (d.containsKey("keyboardType")) {
      boolean autocorrect = true;
      if (d.containsKey("autocorrect")) {
        autocorrect = d.getBoolean("autocorrect");
      }
      handleKeyboardType(d.getInt("keyboardType"), autocorrect);
    }

    if (d.containsKey("autocapitalization")) {

      Capitalize autoCapValue = null;

      switch (d.getInt("autocapitalization")) {
        case TEXT_AUTOCAPITALIZATION_NONE:
          autoCapValue = Capitalize.NONE;
          break;

        case TEXT_AUTOCAPITALIZATION_ALL:
          autoCapValue = Capitalize.CHARACTERS;
          break;

        case TEXT_AUTOCAPITALIZATION_SENTENCES:
          autoCapValue = Capitalize.SENTENCES;
          break;

        case TEXT_AUTOCAPITALIZATION_WORDS:
          autoCapValue = Capitalize.WORDS;
          break;

        default:
          Log.w(
              LCAT, "Unknown AutoCapitalization Value [" + d.getString("autocapitalization") + "]");
          break;
      }

      if (null != autoCapValue) {
        tv.setKeyListener(TextKeyListener.getInstance(false, autoCapValue));
      }
    }

    if (d.containsKey("passwordMask")) {
      if (TiConvert.toBoolean(d.get("passwordMask"))) {
        // This shouldn't be needed but it's belts & braces
        tv.setKeyListener(TextKeyListener.getInstance(false, Capitalize.NONE));
        // Both setTransform & keyboard type are required
        tv.setTransformationMethod(PasswordTransformationMethod.getInstance());
        // We also need to set the keyboard type - otherwise the password mask won't be applied
        handleKeyboardType(KEYBOARD_PASSWORD, false);
      }
    }
  }
  @Override
  public void propertyChanged(String key, Object oldValue, Object newValue, TiProxy proxy) {
    if (DBG) {
      Log.d(LCAT, "Property: " + key + " old: " + oldValue + " new: " + newValue);
    }
    if (key.equals("enabled")) {
      tv.setEnabled(TiConvert.toBoolean(newValue));
    } else if (key.equals("value")) {
      tv.setText((String) newValue);
    } else if (key.equals("color")) {
      tv.setTextColor(TiConvert.toColor((String) newValue));
    } else if (key.equals("passwordMask")) {
      if (TiConvert.toBoolean(newValue) == true) {
        // This shouldn't be needed but it's belts & braces
        tv.setKeyListener(TextKeyListener.getInstance(false, Capitalize.NONE));
        // Both setTransform & keyboard type are required
        tv.setTransformationMethod(PasswordTransformationMethod.getInstance());
        // We also need to set the keyboard type - otherwise the password mask won't be applied
        handleKeyboardType(KEYBOARD_PASSWORD, false);
      } else {
        handleKeyboardType(KEYBOARD_DEFAULT, false);
      }
    } else if (key.equals("hintText")) {
      tv.setHint((String) newValue);
    } else if (key.equals("textAlign") || key.equals("verticalAlign")) {
      String textAlign = null;
      String verticalAlign = null;
      if (key.equals("textAlign")) {
        textAlign = TiConvert.toString(newValue);
      }
      if (key.equals("verticalAlign")) {
        verticalAlign = TiConvert.toString(newValue);
      }
      handleTextAlign(textAlign, verticalAlign);
    } else if (key.equals("autocapitalization")) {

      // TODO Missing
      Capitalize autoCapValue = null;

      switch (TiConvert.toInt(newValue)) {
        case TEXT_AUTOCAPITALIZATION_NONE:
          autoCapValue = Capitalize.NONE;
          break;

        case TEXT_AUTOCAPITALIZATION_ALL:
          autoCapValue = Capitalize.CHARACTERS;
          break;

        case TEXT_AUTOCAPITALIZATION_SENTENCES:
          autoCapValue = Capitalize.SENTENCES;
          break;

        case TEXT_AUTOCAPITALIZATION_WORDS:
          autoCapValue = Capitalize.WORDS;
          break;

        default:
          Log.w(LCAT, "Unknown AutoCapitalization Value [" + TiConvert.toString(newValue) + "]");
          break;
      }

      if (null != autoCapValue) {
        tv.setKeyListener(TextKeyListener.getInstance(false, autoCapValue));
      }

    } else if (key.equals("keyboardType") || (key.equals("autocorrect"))) {
      TiDict d = proxy.getDynamicProperties();
      boolean autocorrect = false;
      if (d.containsKey("autocorrect")) {
        autocorrect = d.getBoolean("autocorrect");
      }

      handleKeyboardType(TiConvert.toInt(d, "keyboardType"), autocorrect);
    } else if (key.equals("returnKeyType")) {
      handleReturnKeyType(TiConvert.toInt(newValue));
    } else if (key.equals("font")) {
      TiUIHelper.styleText(tv, (TiDict) newValue);
    } else {
      super.propertyChanged(key, oldValue, newValue, proxy);
    }
  }