code: package co.infinum.example;
  
  import android.annotation.SuppressLint;
  import android.content.Intent;
  import android.os.Build;
  import android.os.Bundle;
  import android.view.View;
  import android.widget.EditText;
  import android.widget.TextView;
  
  import androidx.annotation.NonNull;
  import androidx.annotation.Nullable;
  import androidx.annotation.RequiresApi;
  import androidx.appcompat.app.AppCompatActivity;
  import co.infinum.goldfinger.Goldfinger;
  
  @RequiresApi(Build.VERSION_CODES.M)
  public abstract class BaseLoginActivity extends AppCompatActivity {
  
      protected abstract void decryptFingerprintPin(String encryptedPin);
      protected abstract void initGoldfinger();
  
      private EditText pinInputView;
      private View pinLoginButton;
      private View fingerprintLoginButton;
      private TextView errorView;
      private View resetButton;
      private MockLoginService loginService = new MockLoginService();
      private MockLoginService.Callback callback = new MockLoginService.Callback() {
          @Override
          public void onFailure() {
              errorView.setVisibility(View.VISIBLE);
              errorView.setText("Invalid PIN");
          }
  
          @Override
          public void onSuccess() {
              navigateToSettings();
          }
      };
  
      protected Goldfinger.PromptParams buildPromptParams() {
          return new Goldfinger.PromptParams.Builder(this)
              .title("Login")
              .description("Confirm Fingerprint to Login")
              .negativeButtonText("Cancel")
              .allowedAuthenticators(SharedPrefs.getAuthenticators())
              .build();
      }
  
      protected void handleGoldfingerError() {
          errorView.setVisibility(View.VISIBLE);
          errorView.setText("Fingerprint exception - check log.");
      }
  
      protected void handleGoldfingerResult(@NonNull Goldfinger.Result result) {
          if (result.type() == Goldfinger.Type.SUCCESS) {
              loginService.login(result.value(), callback);
          } else if (result.type() == Goldfinger.Type.ERROR) {
              errorView.setVisibility(View.VISIBLE);
              String formattedResult = String.format("%s - %s", result.type().toString(), result.reason().toString());
              errorView.setText(formattedResult);
          }
      }
  
      @Override
      protected void onCreate(@Nullable Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_login);
  
          initGoldfinger();
          initViews();
          initListeners();
      }
  
      @Override
      protected void onStart() {
          super.onStart();
  
          pinLoginButton.setEnabled(pinInputView.getText().toString().length() == 4);
          fingerprintLoginButton.setEnabled(SharedPrefs.getFingerprintPin() != null);
      }
  
      @SuppressLint("SetTextI18n")
      private void initListeners() {
          pinInputView.addTextChangedListener(new SimpleTextWatcher() {
              @Override
              public void onTextChanged(String text) {
                  errorView.setVisibility(View.GONE);
                  pinLoginButton.setEnabled(text.length() == 4);
              }
          });
  
          pinLoginButton.setOnClickListener(v -> {
              errorView.setVisibility(View.GONE);
  
              loginService.login(pinInputView.getText().toString(), callback);
          });
  
          fingerprintLoginButton.setOnClickListener(v -> {
              errorView.setVisibility(View.GONE);
              String encryptedPin = SharedPrefs.getFingerprintPin();
              decryptFingerprintPin(encryptedPin);
          });
  
          resetButton.setOnClickListener(v -> {
              SharedPrefs.clear();
              startActivity(new Intent(this, ChooseImplementationActivity.class));
              finish();
          });
      }
  
      private void initViews() {
          pinInputView = findViewById(R.id.pinInputView);
          pinLoginButton = findViewById(R.id.pinLoginButton);
          fingerprintLoginButton = findViewById(R.id.fingerprintLoginButton);
          errorView = findViewById(R.id.errorView);
          resetButton = findViewById(R.id.resetButton);
      }
  
      private void navigateToSettings() {
          Class<?> cls = SharedPrefs.isRxExample() ? RxSettingsActivity.class : SettingsActivity.class;
          startActivity(new Intent(BaseLoginActivity.this, cls));
      }
  }
  