/**
   * Returns the localized description of the action performed by a specified key based on the
   * current keyboard state.
   *
   * @param context The package's context.
   * @param keyboard The keyboard on which the key resides.
   * @param key The key from which to obtain a description.
   * @param shouldObscure {@true} if text (e.g. non-control) characters should be obscured.
   * @return a character sequence describing the action performed by pressing the key
   */
  public String getDescriptionForKey(
      final Context context, final Keyboard keyboard, final Key key, final boolean shouldObscure) {
    final int code = key.getCode();

    if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
      final String description = getDescriptionForSwitchAlphaSymbol(context, keyboard);
      if (description != null) {
        return description;
      }
    }

    if (code == Constants.CODE_SHIFT) {
      return getDescriptionForShiftKey(context, keyboard);
    }

    if (code == Constants.CODE_ENTER) {
      // The following function returns the correct description in all action and
      // regular enter cases, taking care of all modes.
      return getDescriptionForActionKey(context, keyboard, key);
    }

    if (code == Constants.CODE_OUTPUT_TEXT) {
      return key.getOutputText();
    }

    // Just attempt to speak the description.
    if (code != Constants.CODE_UNSPECIFIED) {
      // If the key description should be obscured, now is the time to do it.
      final boolean isDefinedNonCtrl = Character.isDefined(code) && !Character.isISOControl(code);
      if (shouldObscure && isDefinedNonCtrl) {
        return context.getString(OBSCURED_KEY_RES_ID);
      }
      final String description = getDescriptionForCodePoint(context, code);
      if (description != null) {
        return description;
      }
      if (!TextUtils.isEmpty(key.getLabel())) {
        return key.getLabel();
      }
      return context.getString(R.string.spoken_description_unknown);
    }
    return null;
  }
  /**
   * Returns a context-sensitive description of the "Enter" action key.
   *
   * @param context The package's context.
   * @param keyboard The keyboard on which the key resides.
   * @param key The key to describe.
   * @return Returns a context-sensitive description of the "Enter" action key.
   */
  private static String getDescriptionForActionKey(
      final Context context, final Keyboard keyboard, final Key key) {
    final KeyboardId keyboardId = keyboard.mId;
    final int actionId = keyboardId.imeAction();
    final int resId;

    // Always use the label, if available.
    if (!TextUtils.isEmpty(key.getLabel())) {
      return key.getLabel().trim();
    }

    // Otherwise, use the action ID.
    switch (actionId) {
      case EditorInfo.IME_ACTION_SEARCH:
        resId = R.string.spoken_description_search;
        break;
      case EditorInfo.IME_ACTION_GO:
        resId = R.string.label_go_key;
        break;
      case EditorInfo.IME_ACTION_SEND:
        resId = R.string.label_send_key;
        break;
      case EditorInfo.IME_ACTION_NEXT:
        resId = R.string.label_next_key;
        break;
      case EditorInfo.IME_ACTION_DONE:
        resId = R.string.label_done_key;
        break;
      case EditorInfo.IME_ACTION_PREVIOUS:
        resId = R.string.label_previous_key;
        break;
      default:
        resId = R.string.spoken_description_return;
    }
    return context.getString(resId);
  }