@Override
    public View getView(int position, View convertView, ViewGroup parent) {
      LayoutInflater inflater = getLayoutInflater();
      PinInfo currentPin = getItem(position);

      View row;
      if (convertView != null) {
        // Reuse an existing view
        row = convertView;
      } else {
        // Create a new view
        row = inflater.inflate(R.layout.user_row, null);

        // This is a workaround to address the issue on DragSortListView that complex
        // LinearLayout doesn't take the full width.
        // https://github.com/bauerca/drag-sort-listview/issues/73
        row.setLayoutParams(
            new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
      }

      TextView pinView = row.findViewById(R.id.pin_value);
      TextView userView = row.findViewById(R.id.current_user);
      View buttonView = row.findViewById(R.id.next_otp);
      CountdownIndicator countdownIndicator = row.findViewById(R.id.countdown_icon);

      // We only show drag handle on selected item when the number of items is larger than 1.
      boolean showDragHandle = false;
      try {
        if (getMultiSelectListSingleCheckedItemPosition(userList) == position && getCount() >= 2) {
          showDragHandle = true;
        }
      } catch (IllegalStateException ignored) {
        // No pin code is selected.
      }
      row.findViewById(R.id.user_row_drag_handle_image)
          .setVisibility(showDragHandle ? View.VISIBLE : View.GONE);

      if (currentPin.isHotp()) {
        buttonView.setVisibility(View.VISIBLE);
        buttonView.setEnabled(currentPin.isHotpCodeGenerationAllowed());
        ((ViewGroup) row)
            .setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); // makes long press work
        NextOtpButtonListener clickListener = new NextOtpButtonListener(currentPin);
        buttonView.setOnClickListener(clickListener);
        row.setTag(clickListener);

        countdownIndicator.setVisibility(View.GONE);
      } else { // TOTP, so no button needed
        buttonView.setVisibility(View.GONE);
        buttonView.setOnClickListener(null);
        row.setTag(null);

        countdownIndicator.setVisibility(View.VISIBLE);
        countdownIndicator.setPhase(totpCountdownPhase);
      }

      if (getString(R.string.empty_pin).equals(currentPin.getPin())) {
        pinView.setTextScaleX(PIN_TEXT_SCALEX_UNDERSCORE); // smaller gap between underscores
      } else {
        pinView.setTextScaleX(PIN_TEXT_SCALEX_NORMAL);
      }
      pinView.setText(Utilities.getStyledPincode(currentPin.getPin()));
      userView.setText(
          Utilities.getCombinedTextForIssuerAndAccountName(
              currentPin.getIndex().getIssuer(), currentPin.getIndex().getStrippedName()));

      return row;
    }
Displays the user and OTP for the specified position. For HOTP, displays the button for
generating the next OTP value; for TOTP, displays the countdown indicator.
java/com/google/android/apps/authenticator/AuthenticatorActivity.java