Skip to content

Commit

Permalink
Merge pull request #446 from doubleangels/dev
Browse files Browse the repository at this point in the history
Improvements to app lock, add toggle
  • Loading branch information
doubleangels authored Feb 22, 2025
2 parents c28c684 + 9cb4401 commit 9a15ea5
Show file tree
Hide file tree
Showing 33 changed files with 162 additions and 311 deletions.
7 changes: 3 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId "com.doubleangels.nextdnsmanagement"
minSdkVersion 32
targetSdk = 35
versionCode 256
versionName "5.5.7"
versionCode 257
versionName "5.5.8"
resourceConfigurations += ["en", "zh", "nl", "fi", "fr", "de", "in", "it", "ja", "pl", "pt", "es", "sv", "tr"]
}

Expand Down Expand Up @@ -65,7 +65,7 @@ android {
dependencies {
implementation "androidx.activity:activity:1.10.0"
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation "androidx.biometric:biometric:1.2.0-alpha05"
implementation "androidx.biometric:biometric:1.4.0-alpha02"
implementation 'androidx.preference:preference:1.2.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.webkit:webkit:1.12.1'
Expand All @@ -77,7 +77,6 @@ dependencies {
implementation 'com.squareup.retrofit2:converter-gson:2.11.0'
implementation 'de.hdodenhof:circleimageview:3.1.0'
implementation 'io.sentry:sentry-android:8.2.0'
implementation 'jp.wasabeef:blurry:4.0.0'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
}

Expand Down
188 changes: 35 additions & 153 deletions app/src/foss/java/com/doubleangels/nextdnsmanagement/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.view.Window;
import android.webkit.CookieManager;
import android.webkit.WebChromeClient;
Expand Down Expand Up @@ -48,8 +46,6 @@

import java.util.Locale;

import jp.wasabeef.blurry.Blurry;

/**
* Main Activity class that handles initialization of the UI, WebView, and various settings
* such as dark mode and locale. It also includes logic for handling low-memory events,
Expand All @@ -67,7 +63,6 @@ public class MainActivity extends AppCompatActivity {
private Boolean isWebViewInitialized = false;
// Bundle to store and restore the WebView state across configuration changes.
private Bundle webViewState = null;

// Biometric authentication timeout in milliseconds (2 minutes)
private static final long AUTH_TIMEOUT_MS = 2 * 60 * 1000;
// Timestamp (in ms) of the last successful authentication.
Expand Down Expand Up @@ -112,9 +107,6 @@ protected void onCreate(Bundle savedInstanceState) {
// Set the content view for this activity.
setContentView(R.layout.activity_main);

// Apply the blurry overlay immediately to the SwipeRefreshLayout (web content container)
showBlurryOverlay();

// Initialize Sentry manager for error tracking and logging.
SentryManager sentryManager = new SentryManager(this);

Expand Down Expand Up @@ -147,6 +139,11 @@ protected void onCreate(Bundle savedInstanceState) {
// Set up swipe-to-refresh functionality.
setupSwipeToRefreshForActivity();

// Request POST_NOTIFICATIONS permission if not granted already.
if (ContextCompat.checkSelfPermission(this, POST_NOTIFICATIONS) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{POST_NOTIFICATIONS}, 1);
}

// Initialize the WebView and load the main URL.
setupWebViewForActivity(getString(R.string.main_url));
} catch (Exception e) {
Expand Down Expand Up @@ -183,81 +180,50 @@ protected void onPause() {
@Override
protected void onResume() {
super.onResume();
// Resume the WebView if it exists; otherwise, initialize it.
if (webView != null) {
webView.onResume();
} else if (!isWebViewInitialized) {
setupWebViewForActivity(getString(R.string.main_url));
}

// Check if the authentication timeout has expired.
if (shouldAuthenticate()) {
// Hide toolbar buttons and menu items until the user authenticates.
hideToolbarButtons();
invalidateOptionsMenu(); // Update menu visibility based on authentication status.

final BiometricLock biometricLock = new BiometricLock(this);
if (biometricLock.canAuthenticate()) {
// Apply the blur overlay and prompt for biometric authentication.
showBlurryOverlay();
biometricLock.showPrompt(
"Unlock",
"Authenticate to access and change your settings.",
"",
new BiometricLock.BiometricLockCallback() {
@Override
public void onAuthenticationSucceeded() {
// On successful authentication, remove the blur overlay.
removeBlurryOverlay();
// Animate the WebView to full opacity to reveal its content.
if (webView != null) {
webView.animate().alpha(1f).setDuration(300).start();
SharedPreferencesManager.init(this);

if (SharedPreferencesManager.getBoolean("app_lock_enable", true)) {
if (shouldAuthenticate()) {

final BiometricLock biometricLock = new BiometricLock(this);
if (biometricLock.canAuthenticate()) {
biometricLock.showPrompt(
"Unlock",
"Authenticate to access and change your settings.",
"",
new BiometricLock.BiometricLockCallback() {
@Override
public void onAuthenticationSucceeded() {
if (webView != null) {
webView.animate().alpha(1f).setDuration(300).start();
}
lastAuthenticatedTime = System.currentTimeMillis();
invalidateOptionsMenu();
}
// Update the last authentication timestamp.
lastAuthenticatedTime = System.currentTimeMillis();
// Reveal the toolbar buttons and menu items.
showToolbarButtons();
invalidateOptionsMenu();
}

@Override
public void onAuthenticationError(String error) {
// Remove the blur overlay and show an error message.
removeBlurryOverlay();
Toast.makeText(MainActivity.this, "Authentication error!", Toast.LENGTH_SHORT).show();
}
@Override
public void onAuthenticationError(String error) {
finish();
}

@Override
public void onAuthenticationFailed() {
// Inform the user of a failed authentication attempt.
Toast.makeText(MainActivity.this, "Authentication failed. Please try again.", Toast.LENGTH_SHORT).show();
@Override
public void onAuthenticationFailed() {
finish();
}
}
}
);
} else {
// If biometric authentication is not available, update the authentication timestamp,
// and reveal toolbar buttons and menu items.
lastAuthenticatedTime = System.currentTimeMillis();
showToolbarButtons();
invalidateOptionsMenu();
}
} else {
// If no authentication is needed, ensure toolbar buttons and menu items are visible.
showToolbarButtons();
invalidateOptionsMenu();
}

// Fallback: If the WebView's progress is still 0 after a delay, attempt a reload.
if (webView != null && webView.getProgress() == 0) {
webView.postDelayed(() -> {
if (webView.getProgress() == 0) {
Log.d("WebView", "Fallback reload initiated");
webView.reload();
);
}
}, 300);
}
}
}


/**
* Determines whether biometric authentication is required based on the timeout.
*
Expand All @@ -267,43 +233,6 @@ private boolean shouldAuthenticate() {
return System.currentTimeMillis() - lastAuthenticatedTime > AUTH_TIMEOUT_MS;
}

/**
* Applies a blurry overlay over the SwipeRefreshLayout containing the WebView.
* If the container's dimensions are not available yet, delays and retries.
*/
private void showBlurryOverlay() {
final ViewGroup container = findViewById(R.id.swipeRefreshLayout);
// Post a runnable to execute after the layout pass.
container.post(() -> {
// If the container has no valid dimensions, try again after a short delay.
if (container.getWidth() == 0 || container.getHeight() == 0) {
container.postDelayed(this::showBlurryOverlay, 100);
return;
}
try {
// Get the tint color from resources.
int tintColor = ContextCompat.getColor(this, R.color.blur_tint);
// Apply the blur with the specified radius, sampling, and tint color.
Blurry.with(this)
.radius(10)
.sampling(2)
.color(tintColor)
.onto(container);
} catch (NullPointerException e) {
// Log any exceptions that occur while applying the blur.
Log.d("Blurry", "There was an error while applying a blur effect: " + e);
}
});
}

/**
* Removes the blurry overlay from the SwipeRefreshLayout.
*/
private void removeBlurryOverlay() {
ViewGroup container = findViewById(R.id.swipeRefreshLayout);
Blurry.delete(container);
}

/**
* Sets up the status bar by applying a custom background color.
* This method may be updated to handle newer Android versions as needed.
Expand Down Expand Up @@ -443,9 +372,6 @@ public void setupWebViewForActivity(String url) {
// Find the WebView in the layout.
webView = findViewById(R.id.webView);

// Hide the WebView until authentication is complete.
webView.setAlpha(0f);

// Restore the saved WebView state if available; otherwise, load the provided URL.
if (webViewState != null) {
webView.restoreState(webViewState);
Expand Down Expand Up @@ -563,50 +489,6 @@ private void startIntent(Class<?> targetClass) {
startActivity(intent);
}

/**
* Hides all child views (such as buttons) within the toolbar.
*/
private void hideToolbarButtons() {
// Get the toolbar by its ID.
Toolbar toolbar = findViewById(R.id.toolbar);
// Loop through all the child views in the toolbar.
for (int i = 0; i < toolbar.getChildCount(); i++) {
// Hide each child view.
toolbar.getChildAt(i).setVisibility(android.view.View.GONE);
}
}

/**
* Shows all child views (such as buttons) within the toolbar.
*/
private void showToolbarButtons() {
// Get the toolbar by its ID.
Toolbar toolbar = findViewById(R.id.toolbar);
// Loop through all the child views in the toolbar.
for (int i = 0; i < toolbar.getChildCount(); i++) {
// Make each child view visible.
toolbar.getChildAt(i).setVisibility(android.view.View.VISIBLE);
}
}

/**
* Prepares the options menu by updating the visibility of menu items based on the authentication status.
*
* @param menu The options menu to be prepared.
* @return true after the menu has been prepared.
*/
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Determine if the user is authenticated by checking if the elapsed time since the last authentication
// is within the allowed authentication timeout.
boolean isAuthenticated = System.currentTimeMillis() - lastAuthenticatedTime <= AUTH_TIMEOUT_MS;
// Loop through each menu item and set its visibility accordingly.
for (int i = 0; i < menu.size(); i++) {
menu.getItem(i).setVisible(isAuthenticated);
}
return super.onPrepareOptionsMenu(menu);
}

/**
* Initializes the options menu from a resource.
*
Expand Down
Loading

0 comments on commit 9a15ea5

Please sign in to comment.