|
|
|
|
@ -22,6 +22,7 @@ import android.content.IntentFilter;
|
|
|
|
|
import android.content.BroadcastReceiver;
|
|
|
|
|
import android.content.ClipData;
|
|
|
|
|
import android.content.ClipboardManager;
|
|
|
|
|
import android.content.ComponentName;
|
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
|
import android.content.pm.PackageInfo;
|
|
|
|
|
import android.content.pm.PackageManager;
|
|
|
|
|
@ -47,7 +48,6 @@ import android.provider.Settings;
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
import androidx.biometric.BiometricManager;
|
|
|
|
|
import androidx.biometric.BiometricPrompt;
|
|
|
|
|
import androidx.core.app.ActivityCompat;
|
|
|
|
|
import androidx.core.content.ContextCompat;
|
|
|
|
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
@ -55,10 +55,13 @@ import java.io.File;
|
|
|
|
|
import java.io.FileReader;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.PrintWriter;
|
|
|
|
|
import java.util.concurrent.Executor;
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Locale;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
import java.util.concurrent.Executor;
|
|
|
|
|
|
|
|
|
|
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
|
|
|
|
|
private static final String TAG = "IIAB-MainActivity";
|
|
|
|
|
@ -95,11 +98,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
private ProgressBar logProgress;
|
|
|
|
|
|
|
|
|
|
private ActivityResultLauncher<Intent> vpnPermissionLauncher;
|
|
|
|
|
private ActivityResultLauncher<String> requestPermissionLauncher;
|
|
|
|
|
private ActivityResultLauncher<String> notificationPermissionLauncher;
|
|
|
|
|
private ActivityResultLauncher<String[]> requestPermissionsLauncher;
|
|
|
|
|
|
|
|
|
|
private boolean isReadingLogs = false;
|
|
|
|
|
private Handler sizeUpdateHandler = new Handler();
|
|
|
|
|
private final Handler sizeUpdateHandler = new Handler();
|
|
|
|
|
private Runnable sizeUpdateRunnable;
|
|
|
|
|
|
|
|
|
|
private final BroadcastReceiver logReceiver = new BroadcastReceiver() {
|
|
|
|
|
@ -120,38 +122,35 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
prefs = new Preferences(this);
|
|
|
|
|
setContentView(R.layout.main);
|
|
|
|
|
|
|
|
|
|
// Initialize Result Launchers
|
|
|
|
|
// 1. Initialize Result Launchers
|
|
|
|
|
vpnPermissionLauncher = registerForActivityResult(
|
|
|
|
|
new ActivityResultContracts.StartActivityForResult(),
|
|
|
|
|
result -> {
|
|
|
|
|
if (result.getResultCode() == RESULT_OK && prefs.getEnable()) {
|
|
|
|
|
connectVpn();
|
|
|
|
|
}
|
|
|
|
|
// Chain: Check battery after VPN dialog
|
|
|
|
|
checkBatteryOptimizations();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
requestPermissionLauncher = registerForActivityResult(
|
|
|
|
|
new ActivityResultContracts.RequestPermission(),
|
|
|
|
|
isGranted -> {
|
|
|
|
|
if (isGranted) {
|
|
|
|
|
addToLog("Termux RUN_COMMAND permission granted");
|
|
|
|
|
} else {
|
|
|
|
|
addToLog("Termux permission denied. Watchdog stimulus may fail.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
notificationPermissionLauncher = registerForActivityResult(
|
|
|
|
|
new ActivityResultContracts.RequestPermission(),
|
|
|
|
|
isGranted -> {
|
|
|
|
|
if (isGranted) {
|
|
|
|
|
addToLog("Notification permission granted");
|
|
|
|
|
} else {
|
|
|
|
|
addToLog("Notification permission denied. Status visibility may be limited.");
|
|
|
|
|
// Modern ordered permission requester
|
|
|
|
|
requestPermissionsLauncher = registerForActivityResult(
|
|
|
|
|
new ActivityResultContracts.RequestMultiplePermissions(),
|
|
|
|
|
result -> {
|
|
|
|
|
for (Map.Entry<String, Boolean> entry : result.entrySet()) {
|
|
|
|
|
if (entry.getKey().equals(TERMUX_PERMISSION)) {
|
|
|
|
|
addToLog(entry.getValue() ? "Termux permission granted" : "Termux permission denied");
|
|
|
|
|
} else if (entry.getKey().equals(Manifest.permission.POST_NOTIFICATIONS)) {
|
|
|
|
|
addToLog(entry.getValue() ? "Notification permission granted" : "Notification permission denied");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Step 2: After system permissions, request VPN permission
|
|
|
|
|
prepareVpn();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// UI Bindings
|
|
|
|
|
edittext_socks_addr = findViewById(R.id.socks_addr);
|
|
|
|
|
edittext_socks_udp_addr = findViewById(R.id.socks_udp_addr);
|
|
|
|
|
edittext_socks_port = findViewById(R.id.socks_port);
|
|
|
|
|
@ -167,25 +166,40 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
button_apps = findViewById(R.id.apps);
|
|
|
|
|
button_save = findViewById(R.id.save);
|
|
|
|
|
button_control = findViewById(R.id.control);
|
|
|
|
|
|
|
|
|
|
watchdogControl = findViewById(R.id.watchdog_control);
|
|
|
|
|
watchdogControl.setOnClickListener(this);
|
|
|
|
|
|
|
|
|
|
logActions = findViewById(R.id.log_actions);
|
|
|
|
|
Button btnClearLog = findViewById(R.id.btn_clear_log);
|
|
|
|
|
Button btnCopyLog = findViewById(R.id.btn_copy_log);
|
|
|
|
|
btnClearLog.setOnClickListener(this);
|
|
|
|
|
btnCopyLog.setOnClickListener(this);
|
|
|
|
|
|
|
|
|
|
connectionLog = findViewById(R.id.connection_log);
|
|
|
|
|
connectionLog.setMovementMethod(new ScrollingMovementMethod());
|
|
|
|
|
connectionLog.setTextIsSelectable(true);
|
|
|
|
|
|
|
|
|
|
logProgress = findViewById(R.id.log_progress);
|
|
|
|
|
logWarning = findViewById(R.id.log_warning_text);
|
|
|
|
|
logSizeText = findViewById(R.id.log_size_text);
|
|
|
|
|
themeToggle = findViewById(R.id.theme_toggle);
|
|
|
|
|
versionFooter = findViewById(R.id.version_text);
|
|
|
|
|
configLayout = findViewById(R.id.config_layout);
|
|
|
|
|
configLabel = findViewById(R.id.config_label);
|
|
|
|
|
advancedConfig = findViewById(R.id.advanced_config);
|
|
|
|
|
advConfigLabel = findViewById(R.id.adv_config_label);
|
|
|
|
|
logLabel = findViewById(R.id.log_label);
|
|
|
|
|
|
|
|
|
|
// Allow internal scrolling by disabling parent intercept
|
|
|
|
|
// Listeners
|
|
|
|
|
watchdogControl.setOnClickListener(this);
|
|
|
|
|
btnClearLog.setOnClickListener(this);
|
|
|
|
|
btnCopyLog.setOnClickListener(this);
|
|
|
|
|
themeToggle.setOnClickListener(v -> toggleTheme());
|
|
|
|
|
configLabel.setOnClickListener(v -> toggleVisibility(configLayout, configLabel, getString(R.string.configuration_label)));
|
|
|
|
|
advConfigLabel.setOnClickListener(v -> toggleVisibility(advancedConfig, advConfigLabel, getString(R.string.advanced_settings_label)));
|
|
|
|
|
logLabel.setOnClickListener(v -> handleLogToggle());
|
|
|
|
|
checkbox_udp_in_tcp.setOnClickListener(this);
|
|
|
|
|
checkbox_remote_dns.setOnClickListener(this);
|
|
|
|
|
checkbox_global.setOnClickListener(this);
|
|
|
|
|
button_apps.setOnClickListener(this);
|
|
|
|
|
button_save.setOnClickListener(this);
|
|
|
|
|
button_control.setOnClickListener(this);
|
|
|
|
|
|
|
|
|
|
connectionLog.setMovementMethod(new ScrollingMovementMethod());
|
|
|
|
|
connectionLog.setTextIsSelectable(true);
|
|
|
|
|
connectionLog.setOnTouchListener((v, event) -> {
|
|
|
|
|
v.getParent().requestDisallowInterceptTouchEvent(true);
|
|
|
|
|
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
|
|
|
|
|
@ -194,55 +208,12 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
configLayout = findViewById(R.id.config_layout);
|
|
|
|
|
configLabel = findViewById(R.id.config_label);
|
|
|
|
|
configLabel.setOnClickListener(v -> toggleVisibility(configLayout, configLabel, getString(R.string.configuration_label)));
|
|
|
|
|
|
|
|
|
|
advancedConfig = findViewById(R.id.advanced_config);
|
|
|
|
|
advConfigLabel = findViewById(R.id.adv_config_label);
|
|
|
|
|
advConfigLabel.setOnClickListener(v -> toggleVisibility(advancedConfig, advConfigLabel, getString(R.string.advanced_settings_label)));
|
|
|
|
|
|
|
|
|
|
logLabel = findViewById(R.id.log_label);
|
|
|
|
|
logLabel.setOnClickListener(v -> {
|
|
|
|
|
boolean isOpening = connectionLog.getVisibility() == View.GONE;
|
|
|
|
|
if (isOpening) {
|
|
|
|
|
readBlackBoxLogs();
|
|
|
|
|
startLogSizeUpdates();
|
|
|
|
|
} else {
|
|
|
|
|
stopLogSizeUpdates();
|
|
|
|
|
}
|
|
|
|
|
toggleVisibility(connectionLog, logLabel, getString(R.string.connection_log_label));
|
|
|
|
|
logActions.setVisibility(connectionLog.getVisibility());
|
|
|
|
|
if (logSizeText != null) logSizeText.setVisibility(connectionLog.getVisibility());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
themeToggle = findViewById(R.id.theme_toggle);
|
|
|
|
|
themeToggle.setOnClickListener(v -> toggleTheme());
|
|
|
|
|
applySavedTheme();
|
|
|
|
|
|
|
|
|
|
versionFooter = findViewById(R.id.version_text);
|
|
|
|
|
setVersionFooter();
|
|
|
|
|
|
|
|
|
|
checkbox_udp_in_tcp.setOnClickListener(this);
|
|
|
|
|
checkbox_remote_dns.setOnClickListener(this);
|
|
|
|
|
checkbox_global.setOnClickListener(this);
|
|
|
|
|
button_apps.setOnClickListener(this);
|
|
|
|
|
button_save.setOnClickListener(this);
|
|
|
|
|
button_control.setOnClickListener(this);
|
|
|
|
|
updateUI();
|
|
|
|
|
|
|
|
|
|
/* Request permissions */
|
|
|
|
|
checkNotificationPermission();
|
|
|
|
|
checkTermuxPermission();
|
|
|
|
|
checkBatteryOptimizations();
|
|
|
|
|
|
|
|
|
|
/* Request VPN permission */
|
|
|
|
|
Intent intent = VpnService.prepare(MainActivity.this);
|
|
|
|
|
if (intent != null) {
|
|
|
|
|
vpnPermissionLauncher.launch(intent);
|
|
|
|
|
} else if (prefs.getEnable()) {
|
|
|
|
|
connectVpn();
|
|
|
|
|
}
|
|
|
|
|
// Start sequential permission chain
|
|
|
|
|
initiatePermissionChain();
|
|
|
|
|
|
|
|
|
|
addToLog(getString(R.string.app_started));
|
|
|
|
|
|
|
|
|
|
@ -255,20 +226,47 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void checkNotificationPermission() {
|
|
|
|
|
private void initiatePermissionChain() {
|
|
|
|
|
List<String> permissions = new ArrayList<>();
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
|
|
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
|
|
|
|
notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
|
|
|
|
|
permissions.add(Manifest.permission.POST_NOTIFICATIONS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ContextCompat.checkSelfPermission(this, TERMUX_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
|
|
|
|
|
permissions.add(TERMUX_PERMISSION);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!permissions.isEmpty()) {
|
|
|
|
|
requestPermissionsLauncher.launch(permissions.toArray(new String[0]));
|
|
|
|
|
} else {
|
|
|
|
|
prepareVpn();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void checkTermuxPermission() {
|
|
|
|
|
if (ContextCompat.checkSelfPermission(this, TERMUX_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
|
|
|
|
|
requestPermissionLauncher.launch(TERMUX_PERMISSION);
|
|
|
|
|
private void prepareVpn() {
|
|
|
|
|
Intent intent = VpnService.prepare(MainActivity.this);
|
|
|
|
|
if (intent != null) {
|
|
|
|
|
vpnPermissionLauncher.launch(intent);
|
|
|
|
|
} else {
|
|
|
|
|
if (prefs.getEnable()) connectVpn();
|
|
|
|
|
checkBatteryOptimizations();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void handleLogToggle() {
|
|
|
|
|
boolean isOpening = connectionLog.getVisibility() == View.GONE;
|
|
|
|
|
if (isOpening) {
|
|
|
|
|
readBlackBoxLogs();
|
|
|
|
|
startLogSizeUpdates();
|
|
|
|
|
} else {
|
|
|
|
|
stopLogSizeUpdates();
|
|
|
|
|
}
|
|
|
|
|
toggleVisibility(connectionLog, logLabel, getString(R.string.connection_log_label));
|
|
|
|
|
logActions.setVisibility(connectionLog.getVisibility());
|
|
|
|
|
if (logSizeText != null) logSizeText.setVisibility(connectionLog.getVisibility());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void startLogSizeUpdates() {
|
|
|
|
|
sizeUpdateHandler.removeCallbacks(sizeUpdateRunnable);
|
|
|
|
|
sizeUpdateHandler.post(sizeUpdateRunnable);
|
|
|
|
|
@ -302,10 +300,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
private void readBlackBoxLogs() {
|
|
|
|
|
if (isReadingLogs) return;
|
|
|
|
|
isReadingLogs = true;
|
|
|
|
|
|
|
|
|
|
if (logProgress != null) {
|
|
|
|
|
logProgress.setVisibility(View.VISIBLE);
|
|
|
|
|
}
|
|
|
|
|
if (logProgress != null) logProgress.setVisibility(View.VISIBLE);
|
|
|
|
|
|
|
|
|
|
new Thread(() -> {
|
|
|
|
|
File logFile = new File(getFilesDir(), "watchdog_heartbeat_log.txt");
|
|
|
|
|
@ -327,8 +322,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final String result = sb.toString();
|
|
|
|
|
|
|
|
|
|
// Check rapid growth flag
|
|
|
|
|
SharedPreferences internalPrefs = getSharedPreferences("IIAB_Internal", Context.MODE_PRIVATE);
|
|
|
|
|
final boolean isRapid = internalPrefs.getBoolean(IIABWatchdog.PREF_RAPID_GROWTH, false);
|
|
|
|
|
|
|
|
|
|
@ -389,13 +382,20 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
|
|
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
|
|
|
|
if (pm != null && !pm.isIgnoringBatteryOptimizations(getPackageName())) {
|
|
|
|
|
String manufacturer = Build.MANUFACTURER.toLowerCase();
|
|
|
|
|
String message = getString(R.string.battery_opt_msg);
|
|
|
|
|
|
|
|
|
|
if (manufacturer.contains("oppo") || manufacturer.contains("realme")) {
|
|
|
|
|
message += getString(R.string.battery_opt_oppo_extra);
|
|
|
|
|
} else if (manufacturer.contains("xiaomi")) {
|
|
|
|
|
message += getString(R.string.battery_opt_xiaomi_extra);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new AlertDialog.Builder(this)
|
|
|
|
|
.setTitle(R.string.battery_opt_title)
|
|
|
|
|
.setMessage(R.string.battery_opt_msg)
|
|
|
|
|
.setMessage(message)
|
|
|
|
|
.setPositiveButton(R.string.go_to_settings, (dialog, which) -> {
|
|
|
|
|
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
|
|
|
|
intent.setData(Uri.parse("package:" + getPackageName()));
|
|
|
|
|
startActivity(intent);
|
|
|
|
|
openBatterySettings(manufacturer);
|
|
|
|
|
})
|
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
|
.show();
|
|
|
|
|
@ -403,6 +403,42 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void openBatterySettings(String manufacturer) {
|
|
|
|
|
if (manufacturer.contains("oppo") || manufacturer.contains("realme")) {
|
|
|
|
|
try {
|
|
|
|
|
Intent intent = new Intent();
|
|
|
|
|
intent.setComponent(new ComponentName("com.coloros.safecenter",
|
|
|
|
|
"com.coloros.safecenter.permission.startup.StartupAppListActivity"));
|
|
|
|
|
startActivity(intent);
|
|
|
|
|
return;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
try {
|
|
|
|
|
Intent intent = new Intent();
|
|
|
|
|
intent.setComponent(new ComponentName("com.coloros.oppoguardelf",
|
|
|
|
|
"com.coloros.oppoguardelf.Permission.BackgroundAllowAppListActivity"));
|
|
|
|
|
startActivity(intent);
|
|
|
|
|
return;
|
|
|
|
|
} catch (Exception e2) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (manufacturer.contains("xiaomi")) {
|
|
|
|
|
try {
|
|
|
|
|
Intent intent = new Intent("miui.intent.action.APP_BATTERY_SAVER_SETTINGS");
|
|
|
|
|
intent.setComponent(new ComponentName("com.miui.powerkeeper",
|
|
|
|
|
"com.miui.powerkeeper.ui.HiddenAppsConfigActivity"));
|
|
|
|
|
intent.putExtra("package_name", getPackageName());
|
|
|
|
|
intent.putExtra("package_label", getString(R.string.app_name));
|
|
|
|
|
startActivity(intent);
|
|
|
|
|
return;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
|
|
|
|
intent.setData(Uri.parse("package:" + getPackageName()));
|
|
|
|
|
startActivity(intent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void toggleTheme() {
|
|
|
|
|
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
|
|
|
|
|
int currentMode = AppCompatDelegate.getDefaultNightMode();
|
|
|
|
|
@ -455,7 +491,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
protected void onStart() {
|
|
|
|
|
super.onStart();
|
|
|
|
|
IntentFilter filter = new IntentFilter(IIABWatchdog.ACTION_LOG_MESSAGE);
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
|
|
|
registerReceiver(logReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
|
|
|
|
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
|
|
|
registerReceiver(logReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
|
|
|
|
|
} else {
|
|
|
|
|
registerReceiver(logReceiver, filter);
|
|
|
|
|
@ -512,15 +550,12 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
private void resetLogFile() {
|
|
|
|
|
File logFile = new File(getFilesDir(), "watchdog_heartbeat_log.txt");
|
|
|
|
|
try (PrintWriter pw = new PrintWriter(logFile)) {
|
|
|
|
|
pw.print(""); // Truncate file to 0 bytes
|
|
|
|
|
pw.print("");
|
|
|
|
|
connectionLog.setText("");
|
|
|
|
|
addToLog(getString(R.string.log_reset_user));
|
|
|
|
|
|
|
|
|
|
// Clear rapid growth warning
|
|
|
|
|
SharedPreferences internalPrefs = getSharedPreferences("IIAB_Internal", Context.MODE_PRIVATE);
|
|
|
|
|
internalPrefs.edit().putBoolean(IIABWatchdog.PREF_RAPID_GROWTH, false).apply();
|
|
|
|
|
if (logWarning != null) logWarning.setVisibility(View.GONE);
|
|
|
|
|
|
|
|
|
|
updateLogSizeUI();
|
|
|
|
|
Toast.makeText(this, R.string.log_cleared_toast, Toast.LENGTH_SHORT).show();
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
@ -560,16 +595,13 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
showBiometricPrompt();
|
|
|
|
|
} else {
|
|
|
|
|
BiometricManager biometricManager = BiometricManager.from(this);
|
|
|
|
|
|
|
|
|
|
int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL;
|
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
|
|
|
|
authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK | BiometricManager.Authenticators.DEVICE_CREDENTIAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean isSecure = false;
|
|
|
|
|
android.app.KeyguardManager km = (android.app.KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
|
|
|
|
|
if (km != null && km.isDeviceSecure()) isSecure = true;
|
|
|
|
|
|
|
|
|
|
if (biometricManager.canAuthenticate(authenticators) == BiometricManager.BIOMETRIC_SUCCESS || isSecure) {
|
|
|
|
|
addToLog(getString(R.string.user_initiated_conn));
|
|
|
|
|
toggleService(false);
|
|
|
|
|
@ -602,15 +634,12 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
toggleService(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL;
|
|
|
|
|
|
|
|
|
|
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
|
|
|
|
|
.setTitle(getString(R.string.auth_required_title))
|
|
|
|
|
.setSubtitle(getString(R.string.auth_required_subtitle))
|
|
|
|
|
.setAllowedAuthenticators(authenticators)
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
biometricPrompt.authenticate(promptInfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -623,15 +652,12 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
toggleWatchdog(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL;
|
|
|
|
|
|
|
|
|
|
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
|
|
|
|
|
.setTitle(getString(R.string.unlock_watchdog_title))
|
|
|
|
|
.setSubtitle(getString(R.string.unlock_watchdog_subtitle))
|
|
|
|
|
.setAllowedAuthenticators(authenticators)
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
biometricPrompt.authenticate(promptInfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -652,7 +678,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
private void updateUI() {
|
|
|
|
|
boolean vpnActive = prefs.getEnable();
|
|
|
|
|
boolean watchdogActive = prefs.getWatchdogEnable();
|
|
|
|
|
|
|
|
|
|
if (vpnActive) {
|
|
|
|
|
button_control.setText(R.string.control_disable);
|
|
|
|
|
button_control.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.btn_vpn_on));
|
|
|
|
|
@ -660,7 +685,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
button_control.setText(R.string.control_enable);
|
|
|
|
|
button_control.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.btn_vpn_off));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (watchdogActive) {
|
|
|
|
|
watchdogControl.setText(R.string.watchdog_disable);
|
|
|
|
|
watchdogControl.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.btn_watchdog_on));
|
|
|
|
|
@ -668,7 +692,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
watchdogControl.setText(R.string.watchdog_enable);
|
|
|
|
|
watchdogControl.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.btn_watchdog_off));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edittext_socks_addr.setText(prefs.getSocksAddress());
|
|
|
|
|
edittext_socks_udp_addr.setText(prefs.getSocksUdpAddress());
|
|
|
|
|
edittext_socks_port.setText(String.valueOf(prefs.getSocksPort()));
|
|
|
|
|
@ -681,7 +704,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
|
|
|
|
|
checkbox_global.setChecked(prefs.getGlobal());
|
|
|
|
|
checkbox_udp_in_tcp.setChecked(prefs.getUdpInTcp());
|
|
|
|
|
checkbox_remote_dns.setChecked(prefs.getRemoteDns());
|
|
|
|
|
|
|
|
|
|
boolean editable = !vpnActive;
|
|
|
|
|
edittext_socks_addr.setEnabled(editable);
|
|
|
|
|
edittext_socks_port.setEnabled(editable);
|
|
|
|
|
|