content: package amirz.helpers;
  
  import android.annotation.SuppressLint;
  import android.app.Activity;
  import android.app.KeyguardManager;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.Intent;
  import android.hardware.biometrics.BiometricPrompt;
  import android.os.Build;
  import android.os.CancellationSignal;
  import android.os.Handler;
  import android.os.Looper;
  
  import androidx.annotation.NonNull;
  import androidx.annotation.Nullable;
  import androidx.annotation.RequiresApi;
  
  import com.android.launcher3.Utilities;
  
  import java.security.KeyPair;
  import java.security.KeyStore;
  import java.security.PrivateKey;
  import java.security.PublicKey;
  import java.security.Signature;
  import java.util.concurrent.Executor;
  
  import amirz.shade.ShadeLauncher;
  
  import static android.app.Activity.RESULT_OK;
  
  public class SecurityHelper {
      public static final String TAG = "SecurityHelper";
      private static final String KEY_NAME = "test";
      public static final int REQUEST_CONFIRM_CREDENTIALS = 007;
      public static final int REQUEST_CONFIRM_AUTH = 1212;
  
      private final String mToBeSignedMessage;
      private final KeyguardManager mKeyguardManager;
  
      public Activity mActivity;
  
      public interface SecurityCallback {
          void onActivityResult(int requestCode, int resultCode, Intent data);
      }
  
      public SecurityHelper(Activity activity){
          mActivity = activity;
          mKeyguardManager = (KeyguardManager) mActivity.getSystemService(Context.KEYGUARD_SERVICE);
          // Init signature
          Signature signature;
          try {
              // Send key name and challenge to the server, this message will be verified with registered public key on the server
              mToBeSignedMessage = new StringBuilder()
                      .append(KEY_NAME)
                      .append(":")
                      // Generated by the server to protect against replay attack
                      .append("12345")
                      .toString();
              signature = initSignature(KEY_NAME);
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      @Nullable
      private KeyPair getKeyPair(String keyName) throws Exception {
          KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
          keyStore.load(null);
          if (keyStore.containsAlias(keyName)) {
              // Get public key
              PublicKey publicKey = keyStore.getCertificate(keyName).getPublicKey();
              // Get private key
              PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyName, null);
              // Return a key pair
              return new KeyPair(publicKey, privateKey);
          }
          return null;
      }
  
      @Nullable
      private Signature initSignature (String keyName) throws Exception {
          KeyPair keyPair = getKeyPair(keyName);
  
          if (keyPair != null) {
              Signature signature = Signature.getInstance("SHA256withECDSA");
              signature.initSign(keyPair.getPrivate());
              return signature;
          }
          return null;
      }
  
      public boolean isDeviceSecure(){
          if(Utilities.ATLEAST_MARSHMALLOW){
              return mKeyguardManager.isDeviceSecure();
          } else {
              return mKeyguardManager.isKeyguardSecure();
          }
      }
  
      public void authenticate(String title, String description, int requestCode){
          if (isDeviceSecure()) {
              authenticateKeyguard(title, description, requestCode);
          }
      }
  
      public void authenticateKeyguard(String title, String description, int requestCode){
          Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(title, description);
          if (intent != null) {
              mActivity.startActivityForResult(intent, requestCode);
          }
      }
  
      @SuppressLint("MissingPermission")
      @RequiresApi(api = Build.VERSION_CODES.P)
      public void authenticateBiometric(String title, String description, int requestCode){
          Executor executor;
          if (Utilities.ATLEAST_P) {
              executor = mActivity.getMainExecutor();
          } else {
              final Handler handler = new Handler(Looper.getMainLooper());
              executor = new Executor() {
                  @Override
                  public void execute(@NonNull Runnable command) {
                      handler.post(command);
                  }
              };
          }
          BiometricPrompt.AuthenticationCallback callback = new BiometricPrompt.AuthenticationCallback() {
              @Override
              public void onAuthenticationError(int errorCode,
                                                @NonNull CharSequence errString) {
                  super.onAuthenticationError(errorCode, errString);
                  onError();
              }
  
              @Override
              public void onAuthenticationSucceeded(
                      @NonNull BiometricPrompt.AuthenticationResult result) {
                  super.onAuthenticationSucceeded(result);
                  onSuccess(requestCode);
              }
  
              @Override
              public void onAuthenticationFailed() {
                  super.onAuthenticationFailed();
                  onError();
              }
          };
          BiometricPrompt.Builder builder = new BiometricPrompt.Builder(mActivity)
                  .setTitle(title).setSubtitle(description)
                  .setNegativeButton("Cancel", executor, new DialogInterface.OnClickListener() {
                      @Override
                      public void onClick(DialogInterface dialog, int which) {
                          onCancelled();
                      }
                  });
          if(Utilities.ATLEAST_R){
              builder.setConfirmationRequired(true);
          }
          builder.build().authenticate(new CancellationSignal(), executor, callback);
      }
  
      private void onError() {
  
      }
  
      private void onCancelled() {
  
      }
  
      private void onSuccess(int requestCode) {
          ((ShadeLauncher)mActivity).onSecurityActivityResult(requestCode, RESULT_OK, null);
      }
  }