all go to app info for baterry settings

This commit is contained in:
Luis Guzmán 2026-03-07 01:32:36 -06:00
parent 3c1b920d42
commit 177b025139
2 changed files with 52 additions and 126 deletions

View File

@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-03-07T04:28:01.557850134Z"> <DropdownSelection timestamp="2026-03-07T07:26:40.093624067Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=a026a310" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=RF8Y80CE2DA" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

View File

@ -129,12 +129,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
if (result.getResultCode() == RESULT_OK && prefs.getEnable()) { if (result.getResultCode() == RESULT_OK && prefs.getEnable()) {
connectVpn(); connectVpn();
} }
// Chain: Check battery after VPN dialog
checkBatteryOptimizations(); checkBatteryOptimizations();
} }
); );
// Modern ordered permission requester
requestPermissionsLauncher = registerForActivityResult( requestPermissionsLauncher = registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultContracts.RequestMultiplePermissions(),
result -> { result -> {
@ -145,7 +143,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
addToLog(entry.getValue() ? "Notification permission granted" : "Notification permission denied"); addToLog(entry.getValue() ? "Notification permission granted" : "Notification permission denied");
} }
} }
// Step 2: After system permissions, request VPN permission
prepareVpn(); prepareVpn();
} }
); );
@ -211,8 +208,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
applySavedTheme(); applySavedTheme();
setVersionFooter(); setVersionFooter();
updateUI(); updateUI();
// Start sequential permission chain
initiatePermissionChain(); initiatePermissionChain();
addToLog(getString(R.string.app_started)); addToLog(getString(R.string.app_started));
@ -394,9 +389,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setTitle(R.string.battery_opt_title) .setTitle(R.string.battery_opt_title)
.setMessage(message) .setMessage(message)
.setPositiveButton(R.string.go_to_settings, (dialog, which) -> { .setPositiveButton(R.string.go_to_settings, (dialog, which) -> openBatterySettings(manufacturer))
openBatterySettings(manufacturer);
})
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show(); .show();
} }
@ -407,34 +400,29 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
if (manufacturer.contains("oppo") || manufacturer.contains("realme")) { if (manufacturer.contains("oppo") || manufacturer.contains("realme")) {
try { try {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setComponent(new ComponentName("com.coloros.safecenter", intent.setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity"));
"com.coloros.safecenter.permission.startup.StartupAppListActivity"));
startActivity(intent); startActivity(intent);
return; return;
} catch (Exception e) { } catch (Exception e) {
try { try {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setComponent(new ComponentName("com.coloros.oppoguardelf", intent.setComponent(new ComponentName("com.coloros.oppoguardelf", "com.coloros.oppoguardelf.Permission.BackgroundAllowAppListActivity"));
"com.coloros.oppoguardelf.Permission.BackgroundAllowAppListActivity"));
startActivity(intent); startActivity(intent);
return; return;
} catch (Exception e2) { } catch (Exception e2) {}
}
} }
} else if (manufacturer.contains("xiaomi")) { } else if (manufacturer.contains("xiaomi")) {
try { try {
Intent intent = new Intent("miui.intent.action.APP_BATTERY_SAVER_SETTINGS"); Intent intent = new Intent("miui.intent.action.APP_BATTERY_SAVER_SETTINGS");
intent.setComponent(new ComponentName("com.miui.powerkeeper", intent.setComponent(new ComponentName("com.miui.powerkeeper", "com.miui.powerkeeper.ui.HiddenAppsConfigActivity"));
"com.miui.powerkeeper.ui.HiddenAppsConfigActivity"));
intent.putExtra("package_name", getPackageName()); intent.putExtra("package_name", getPackageName());
intent.putExtra("package_label", getString(R.string.app_name)); intent.putExtra("package_label", getString(R.string.app_name));
startActivity(intent); startActivity(intent);
return; return;
} catch (Exception e) { } catch (Exception e) {}
}
} }
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName())); intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent); startActivity(intent);
} }
@ -442,20 +430,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
private void toggleTheme() { private void toggleTheme() {
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE); SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
int currentMode = AppCompatDelegate.getDefaultNightMode(); int currentMode = AppCompatDelegate.getDefaultNightMode();
int nextMode; int nextMode = (currentMode == AppCompatDelegate.MODE_NIGHT_NO) ? AppCompatDelegate.MODE_NIGHT_YES :
(currentMode == AppCompatDelegate.MODE_NIGHT_YES) ? AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM : AppCompatDelegate.MODE_NIGHT_NO;
if (currentMode == AppCompatDelegate.MODE_NIGHT_NO) { sharedPref.edit().putInt("ui_mode", nextMode).apply();
nextMode = AppCompatDelegate.MODE_NIGHT_YES;
} else if (currentMode == AppCompatDelegate.MODE_NIGHT_YES) {
nextMode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
} else {
nextMode = AppCompatDelegate.MODE_NIGHT_NO;
}
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("ui_mode", nextMode);
editor.apply();
AppCompatDelegate.setDefaultNightMode(nextMode); AppCompatDelegate.setDefaultNightMode(nextMode);
updateThemeToggleButton(nextMode); updateThemeToggleButton(nextMode);
} }
@ -468,32 +445,22 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
private void updateThemeToggleButton(int mode) { private void updateThemeToggleButton(int mode) {
if (mode == AppCompatDelegate.MODE_NIGHT_NO) { if (mode == AppCompatDelegate.MODE_NIGHT_NO) themeToggle.setImageResource(R.drawable.ic_theme_dark);
themeToggle.setImageResource(R.drawable.ic_theme_dark); else if (mode == AppCompatDelegate.MODE_NIGHT_YES) themeToggle.setImageResource(R.drawable.ic_theme_light);
} else if (mode == AppCompatDelegate.MODE_NIGHT_YES) { else themeToggle.setImageResource(R.drawable.ic_theme_system);
themeToggle.setImageResource(R.drawable.ic_theme_light);
} else {
themeToggle.setImageResource(R.drawable.ic_theme_system);
}
} }
private void toggleVisibility(View view, TextView label, String text) { private void toggleVisibility(View view, TextView label, String text) {
if (view.getVisibility() == View.GONE) { boolean isGone = view.getVisibility() == View.GONE;
view.setVisibility(View.VISIBLE); view.setVisibility(isGone ? View.VISIBLE : View.GONE);
label.setText("" + text); label.setText((isGone ? "" : "") + text);
} else {
view.setVisibility(View.GONE);
label.setText("" + text);
}
} }
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
IntentFilter filter = new IntentFilter(IIABWatchdog.ACTION_LOG_MESSAGE); IntentFilter filter = new IntentFilter(IIABWatchdog.ACTION_LOG_MESSAGE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(logReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(logReceiver, filter, Context.RECEIVER_NOT_EXPORTED); registerReceiver(logReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
} else { } else {
registerReceiver(logReceiver, filter); registerReceiver(logReceiver, filter);
@ -503,11 +470,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override @Override
protected void onStop() { protected void onStop() {
super.onStop(); super.onStop();
try { try { unregisterReceiver(logReceiver); } catch (Exception e) {}
unregisterReceiver(logReceiver);
} catch (Exception e) {
// Ignore
}
stopLogSizeUpdates(); stopLogSizeUpdates();
} }
@ -522,13 +485,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
savePrefs(); savePrefs();
Toast.makeText(this, R.string.saved_toast, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.saved_toast, Toast.LENGTH_SHORT).show();
addToLog(getString(R.string.settings_saved)); addToLog(getString(R.string.settings_saved));
} else if (view.getId() == R.id.control) { } else if (view.getId() == R.id.control) handleControlClick();
handleControlClick(); else if (view.getId() == R.id.watchdog_control) handleWatchdogClick();
} else if (view.getId() == R.id.watchdog_control) { else if (view.getId() == R.id.btn_clear_log) showResetLogConfirmation();
handleWatchdogClick(); else if (view.getId() == R.id.btn_copy_log) {
} else if (view.getId() == R.id.btn_clear_log) {
showResetLogConfirmation();
} else if (view.getId() == R.id.btn_copy_log) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("IIAB Log", connectionLog.getText().toString()); ClipData clip = ClipData.newPlainText("IIAB Log", connectionLog.getText().toString());
if (clipboard != null) { if (clipboard != null) {
@ -543,8 +503,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
.setTitle(R.string.log_reset_confirm_title) .setTitle(R.string.log_reset_confirm_title)
.setMessage(R.string.log_reset_confirm_msg) .setMessage(R.string.log_reset_confirm_msg)
.setPositiveButton(R.string.reset_log, (dialog, which) -> resetLogFile()) .setPositiveButton(R.string.reset_log, (dialog, which) -> resetLogFile())
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null).show();
.show();
} }
private void resetLogFile() { private void resetLogFile() {
@ -553,8 +512,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
pw.print(""); pw.print("");
connectionLog.setText(""); connectionLog.setText("");
addToLog(getString(R.string.log_reset_user)); addToLog(getString(R.string.log_reset_user));
SharedPreferences internalPrefs = getSharedPreferences("IIAB_Internal", Context.MODE_PRIVATE); getSharedPreferences("IIAB_Internal", Context.MODE_PRIVATE).edit().putBoolean(IIABWatchdog.PREF_RAPID_GROWTH, false).apply();
internalPrefs.edit().putBoolean(IIABWatchdog.PREF_RAPID_GROWTH, false).apply();
if (logWarning != null) logWarning.setVisibility(View.GONE); if (logWarning != null) logWarning.setVisibility(View.GONE);
updateLogSizeUI(); updateLogSizeUI();
Toast.makeText(this, R.string.log_cleared_toast, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.log_cleared_toast, Toast.LENGTH_SHORT).show();
@ -564,12 +522,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
private void handleWatchdogClick() { private void handleWatchdogClick() {
boolean isEnabled = prefs.getWatchdogEnable(); if (prefs.getWatchdogEnable()) showWatchdogBiometricPrompt();
if (isEnabled) { else toggleWatchdog(false);
showWatchdogBiometricPrompt();
} else {
toggleWatchdog(false);
}
} }
private void toggleWatchdog(boolean stop) { private void toggleWatchdog(boolean stop) {
@ -579,35 +533,24 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
stopService(intent); stopService(intent);
addToLog(getString(R.string.watchdog_stopped)); addToLog(getString(R.string.watchdog_stopped));
} else { } else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) startForegroundService(intent.setAction(WatchdogService.ACTION_START));
startForegroundService(intent.setAction(WatchdogService.ACTION_START)); else startService(intent.setAction(WatchdogService.ACTION_START));
} else {
startService(intent.setAction(WatchdogService.ACTION_START));
}
addToLog(getString(R.string.watchdog_started)); addToLog(getString(R.string.watchdog_started));
} }
updateUI(); updateUI();
} }
private void handleControlClick() { private void handleControlClick() {
boolean isCurrentlyEnabled = prefs.getEnable(); if (prefs.getEnable()) showBiometricPrompt();
if (isCurrentlyEnabled) { else {
showBiometricPrompt(); BiometricManager bm = BiometricManager.from(this);
} else { int auth = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL;
BiometricManager biometricManager = BiometricManager.from(this); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) auth = BiometricManager.Authenticators.BIOMETRIC_WEAK | BiometricManager.Authenticators.DEVICE_CREDENTIAL;
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); android.app.KeyguardManager km = (android.app.KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (km != null && km.isDeviceSecure()) isSecure = true; if (bm.canAuthenticate(auth) == BiometricManager.BIOMETRIC_SUCCESS || (km != null && km.isDeviceSecure())) {
if (biometricManager.canAuthenticate(authenticators) == BiometricManager.BIOMETRIC_SUCCESS || isSecure) {
addToLog(getString(R.string.user_initiated_conn)); addToLog(getString(R.string.user_initiated_conn));
toggleService(false); toggleService(false);
} else { } else showEnrollmentDialog();
showEnrollmentDialog();
}
} }
} }
@ -624,9 +567,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
private void showBiometricPrompt() { private void showBiometricPrompt() {
Executor executor = ContextCompat.getMainExecutor(this); Executor ex = ContextCompat.getMainExecutor(this);
BiometricPrompt biometricPrompt = new BiometricPrompt(MainActivity.this, BiometricPrompt bp = new BiometricPrompt(this, ex, new BiometricPrompt.AuthenticationCallback() {
executor, new BiometricPrompt.AuthenticationCallback() {
@Override @Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result); super.onAuthenticationSucceeded(result);
@ -634,45 +576,30 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
toggleService(true); toggleService(true);
} }
}); });
int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL; int auth = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL;
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder() bp.authenticate(new BiometricPrompt.PromptInfo.Builder().setTitle(getString(R.string.auth_required_title)).setSubtitle(getString(R.string.auth_required_subtitle)).setAllowedAuthenticators(auth).build());
.setTitle(getString(R.string.auth_required_title))
.setSubtitle(getString(R.string.auth_required_subtitle))
.setAllowedAuthenticators(authenticators)
.build();
biometricPrompt.authenticate(promptInfo);
} }
private void showWatchdogBiometricPrompt() { private void showWatchdogBiometricPrompt() {
Executor executor = ContextCompat.getMainExecutor(this); Executor ex = ContextCompat.getMainExecutor(this);
BiometricPrompt biometricPrompt = new BiometricPrompt(this, executor, new BiometricPrompt.AuthenticationCallback() { BiometricPrompt bp = new BiometricPrompt(this, ex, new BiometricPrompt.AuthenticationCallback() {
@Override @Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result); super.onAuthenticationSucceeded(result);
toggleWatchdog(true); toggleWatchdog(true);
} }
}); });
int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL; int auth = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL;
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder() bp.authenticate(new BiometricPrompt.PromptInfo.Builder().setTitle(getString(R.string.unlock_watchdog_title)).setSubtitle(getString(R.string.unlock_watchdog_subtitle)).setAllowedAuthenticators(auth).build());
.setTitle(getString(R.string.unlock_watchdog_title))
.setSubtitle(getString(R.string.unlock_watchdog_subtitle))
.setAllowedAuthenticators(authenticators)
.build();
biometricPrompt.authenticate(promptInfo);
} }
private void toggleService(boolean isEnable) { private void toggleService(boolean stop) {
prefs.setEnable(!isEnable); prefs.setEnable(!stop);
savePrefs(); savePrefs();
updateUI(); updateUI();
Intent intent = new Intent(this, TProxyService.class); Intent intent = new Intent(this, TProxyService.class);
if (isEnable) { startService(intent.setAction(stop ? TProxyService.ACTION_DISCONNECT : TProxyService.ACTION_CONNECT));
startService(intent.setAction(TProxyService.ACTION_DISCONNECT)); addToLog(getString(stop ? R.string.vpn_stopping : R.string.vpn_starting));
addToLog(getString(R.string.vpn_stopping));
} else {
startService(intent.setAction(TProxyService.ACTION_CONNECT));
addToLog(getString(R.string.vpn_starting));
}
} }
private void updateUI() { private void updateUI() {
@ -739,9 +666,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
private void scrollToBottom() { private void scrollToBottom() {
if (connectionLog.getLayout() != null) { if (connectionLog.getLayout() != null) {
final int scrollAmount = connectionLog.getLayout().getLineTop(connectionLog.getLineCount()) - connectionLog.getHeight(); int scroll = connectionLog.getLayout().getLineTop(connectionLog.getLineCount()) - connectionLog.getHeight();
if (scrollAmount > 0) if (scroll > 0) connectionLog.scrollTo(0, scroll);
connectionLog.scrollTo(0, scrollAmount);
} }
} }
} }