diff --git a/app/build.gradle b/app/build.gradle
index b07f0e7b..3cc8fd32 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -54,14 +54,14 @@ configurations {
}
dependencies {
- def lifecycle_version = '2.3.0-rc01'
+ def lifecycle_version = '2.3.0'
def markwon_version = '4.6.1'
def work_version = "2.5.0"
def acra = "5.7.0"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.3.0-beta01'
- implementation 'com.google.android.material:material:1.3.0-alpha03' // Upgrading to rc01 results in failing builds
+ implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
@@ -112,5 +112,6 @@ dependencies {
implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2"
implementation "org.codeberg.gitnex:tea4j:1.0.1"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.1"
+ implementation 'androidx.biometric:biometric:1.1.0'
}
diff --git a/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java b/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java
index 0a3657aa..fcec209f 100644
--- a/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java
@@ -77,7 +77,6 @@ public abstract class BaseActivity extends AppCompatActivity {
}
AppUtil.setAppLocale(getResources(), tinyDB.getString("locale"));
-
}
}
diff --git a/app/src/main/java/org/mian/gitnex/activities/MainActivity.java b/app/src/main/java/org/mian/gitnex/activities/MainActivity.java
index 61cff226..b02a2740 100644
--- a/app/src/main/java/org/mian/gitnex/activities/MainActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/MainActivity.java
@@ -18,6 +18,8 @@ import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
+import androidx.biometric.BiometricPrompt;
+import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
@@ -58,6 +60,7 @@ import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
import eightbitlab.com.blurview.BlurView;
import eightbitlab.com.blurview.RenderScriptBlur;
import retrofit2.Call;
@@ -158,6 +161,43 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
break;
}
+ // biometric auth
+ if(tinyDB.getBoolean("biometricStatus")) {
+
+ Executor executor = ContextCompat.getMainExecutor(this);
+
+ BiometricPrompt biometricPrompt = new BiometricPrompt(this, executor, new BiometricPrompt.AuthenticationCallback() {
+
+ @Override
+ public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
+
+ super.onAuthenticationError(errorCode, errString);
+
+ // Authentication error, close the app
+ if(errorCode == BiometricPrompt.ERROR_USER_CANCELED ||
+ errorCode == BiometricPrompt.ERROR_NEGATIVE_BUTTON) {
+
+ finish();
+ }
+ }
+
+ // Authentication succeeded, continue to app
+ @Override public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); }
+
+ // Authentication failed, close the app
+ @Override public void onAuthenticationFailed() { super.onAuthenticationFailed(); }
+
+ });
+
+ BiometricPrompt.PromptInfo biometricPromptBuilder = new BiometricPrompt.PromptInfo.Builder()
+ .setTitle(getString(R.string.biometricAuthTitle))
+ .setSubtitle(getString(R.string.biometricAuthSubTitle))
+ .setNegativeButtonText(getString(R.string.cancelButton)).build();
+
+ biometricPrompt.authenticate(biometricPromptBuilder);
+
+ }
+
toolbarTitle.setTypeface(myTypeface);
setSupportActionBar(toolbar);
diff --git a/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java b/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java
index ad86d2ab..0e81ccb0 100644
--- a/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java
@@ -1,7 +1,9 @@
package org.mian.gitnex.activities;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
@@ -9,6 +11,8 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
+import androidx.biometric.BiometricManager;
+import com.google.android.material.switchmaterial.SwitchMaterial;
import org.apache.commons.io.FileUtils;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsSecurityBinding;
@@ -16,6 +20,8 @@ import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.ssl.MemorizingTrustManager;
import java.io.File;
import java.io.IOException;
+import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG;
+import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
/**
* Author M M Arif
@@ -53,6 +59,8 @@ public class SettingsSecurityActivity extends BaseActivity {
LinearLayout cacheSizeImagesFrame = activitySettingsSecurityBinding.cacheSizeImagesSelectionFrame;
LinearLayout clearCacheFrame = activitySettingsSecurityBinding.clearCacheSelectionFrame;
+ SwitchMaterial switchBiometric = activitySettingsSecurityBinding.switchBiometric;
+
if(!tinyDB.getString("cacheSizeStr").isEmpty()) {
cacheSizeDataSelected.setText(tinyDB.getString("cacheSizeStr"));
@@ -73,6 +81,70 @@ public class SettingsSecurityActivity extends BaseActivity {
cacheSizeImagesSelectedChoice = tinyDB.getInt("cacheSizeImagesId");
}
+ switchBiometric.setChecked(tinyDB.getBoolean("biometricStatus"));
+
+ // biometric switcher
+ switchBiometric.setOnCheckedChangeListener((buttonView, isChecked) -> {
+
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+
+ if(isChecked) {
+
+ BiometricManager biometricManager = BiometricManager.from(ctx);
+ KeyguardManager keyguardManager = (KeyguardManager) ctx.getSystemService(Context.KEYGUARD_SERVICE);
+
+ if (!keyguardManager.isDeviceSecure()) {
+
+ switch(biometricManager.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)) {
+
+ case BiometricManager.BIOMETRIC_SUCCESS:
+
+ tinyDB.putBoolean("biometricStatus", true);
+ Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
+ break;
+ case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
+ case BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
+ case BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED:
+ case BiometricManager.BIOMETRIC_STATUS_UNKNOWN:
+
+ tinyDB.putBoolean("biometricStatus", false);
+ switchBiometric.setChecked(false);
+ Toasty.error(appCtx, getResources().getString(R.string.biometricNotSupported));
+ break;
+ case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
+
+ tinyDB.putBoolean("biometricStatus", false);
+ switchBiometric.setChecked(false);
+ Toasty.error(appCtx, getResources().getString(R.string.biometricNotAvailable));
+ break;
+ case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
+
+ tinyDB.putBoolean("biometricStatus", false);
+ switchBiometric.setChecked(false);
+ Toasty.info(appCtx, getResources().getString(R.string.enrollBiometric));
+ break;
+ }
+ }
+ else {
+
+ tinyDB.putBoolean("biometricStatus", true);
+ Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
+ }
+ }
+ else {
+
+ tinyDB.putBoolean("biometricStatus", false);
+ Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
+ }
+ }
+ else {
+
+ tinyDB.putBoolean("biometricStatus", false);
+ Toasty.success(appCtx, getResources().getString(R.string.biometricNotSupported));
+ }
+
+ });
+
// clear cache setter
File cacheDir = appCtx.getCacheDir();
clearCacheSelected.setText(FileUtils.byteCountToDisplaySize((int) FileUtils.sizeOfDirectory(cacheDir)));
diff --git a/app/src/main/java/org/mian/gitnex/core/MainApplication.java b/app/src/main/java/org/mian/gitnex/core/MainApplication.java
index f786007d..ceed209a 100644
--- a/app/src/main/java/org/mian/gitnex/core/MainApplication.java
+++ b/app/src/main/java/org/mian/gitnex/core/MainApplication.java
@@ -123,5 +123,12 @@ public class MainApplication extends Application {
tinyDB.putInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay);
}
+
+ // disable biometric by default
+ if(tinyDB.getString("biometricStatusInit").isEmpty()) {
+
+ tinyDB.putBoolean("biometricStatus", false);
+ tinyDB.putString("biometricStatusInit", "yes");
+ }
}
}
diff --git a/app/src/main/res/layout/activity_add_collaborator_to_repository.xml b/app/src/main/res/layout/activity_add_collaborator_to_repository.xml
index df68bdb9..ab0394e0 100644
--- a/app/src/main/res/layout/activity_add_collaborator_to_repository.xml
+++ b/app/src/main/res/layout/activity_add_collaborator_to_repository.xml
@@ -42,11 +42,12 @@
-
diff --git a/app/src/main/res/layout/activity_add_new_team_member.xml b/app/src/main/res/layout/activity_add_new_team_member.xml
index cb09ba62..95ca58e1 100644
--- a/app/src/main/res/layout/activity_add_new_team_member.xml
+++ b/app/src/main/res/layout/activity_add_new_team_member.xml
@@ -42,12 +42,13 @@
-
-
-
-
diff --git a/app/src/main/res/layout/activity_file_diff.xml b/app/src/main/res/layout/activity_file_diff.xml
index 9c465288..2268bb74 100644
--- a/app/src/main/res/layout/activity_file_diff.xml
+++ b/app/src/main/res/layout/activity_file_diff.xml
@@ -61,11 +61,12 @@
-
diff --git a/app/src/main/res/layout/activity_file_view.xml b/app/src/main/res/layout/activity_file_view.xml
index aff93f71..57e080b2 100644
--- a/app/src/main/res/layout/activity_file_view.xml
+++ b/app/src/main/res/layout/activity_file_view.xml
@@ -45,11 +45,12 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_issues.xml b/app/src/main/res/layout/fragment_issues.xml
index e8237bd6..fb1aa9ec 100644
--- a/app/src/main/res/layout/fragment_issues.xml
+++ b/app/src/main/res/layout/fragment_issues.xml
@@ -20,19 +20,21 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_organizations.xml b/app/src/main/res/layout/fragment_organizations.xml
index d14654ef..e7a0ae12 100644
--- a/app/src/main/res/layout/fragment_organizations.xml
+++ b/app/src/main/res/layout/fragment_organizations.xml
@@ -19,11 +19,12 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_repositories.xml b/app/src/main/res/layout/fragment_repositories.xml
index a3b7ea53..91ca3bc7 100644
--- a/app/src/main/res/layout/fragment_repositories.xml
+++ b/app/src/main/res/layout/fragment_repositories.xml
@@ -21,11 +21,12 @@
-
-
-
-
-
-
@style/customOverflowMenuStyle
- @color/lightThemeInputBackground
- @style/inputsMaterialComponentCorner
+ - @style/WindowAnimationTransition
@@ -79,6 +80,7 @@
- @style/customOverflowMenuStyle
- @color/retroThemeInputBackground
- @style/inputsMaterialComponentCorner
+ - @style/WindowAnimationTransition
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c920d761..41bc002c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -275,6 +275,7 @@
Choose what screen should be loaded if the app cannot handle external links. It will redirect you automatically.
N/A
Select Default Link Handler Screen
+ Biometric Support
No more data available
@@ -733,5 +734,12 @@
White on Grey
Dark on White
+ Biometric Authentication
+ Unlock using your biometric credentials
+ No biometric features available on this device
+ Biometric features are currently unavailable
+ Enroll biometric from phone settings
+
Login ID \'%s\' copied to clipboard
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index a2af303a..58880a3f 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -38,6 +38,7 @@
- @style/customOverflowMenuStyle
- @color/inputBackground
- @style/inputsMaterialComponentCorner
+ - @style/WindowAnimationTransition
@@ -78,6 +79,7 @@
- @style/customOverflowMenuStyle
- @color/lightThemeInputBackground
- @style/inputsMaterialComponentCorner
+ - @style/WindowAnimationTransition
@@ -118,6 +120,7 @@
- @style/customOverflowMenuStyle
- @color/retroThemeInputBackground
- @style/inputsMaterialComponentCorner
+ - @style/WindowAnimationTransition
@@ -158,6 +161,7 @@
- @style/customOverflowMenuStyle
- @color/inputBackground
- @style/inputsMaterialComponentCorner
+ - @style/WindowAnimationTransition
@@ -271,6 +275,11 @@
- ?attr/iconsColor
+
+