Mult proto + new app
This commit is contained in:
@@ -361,9 +361,10 @@ public class DragonService extends VpnService {
|
||||
if (process != null) {
|
||||
try {
|
||||
process.destroy();
|
||||
if (!process.waitFor(1200, TimeUnit.MILLISECONDS)) {
|
||||
// Process.waitFor(long, TimeUnit) is API 26; minSdk is 24.
|
||||
if (!awaitExit(process, 1200)) {
|
||||
process.destroyForcibly();
|
||||
process.waitFor(800, TimeUnit.MILLISECONDS);
|
||||
awaitExit(process, 800);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
try { process.destroyForcibly(); } catch (Throwable ignored2) {}
|
||||
@@ -371,6 +372,25 @@ public class DragonService extends VpnService {
|
||||
}
|
||||
}
|
||||
|
||||
/** Waits up to timeoutMs for the process to exit, without needing API 26. */
|
||||
private static boolean awaitExit(Process process, long timeoutMs) throws InterruptedException {
|
||||
long deadline = System.currentTimeMillis() + timeoutMs;
|
||||
while (System.currentTimeMillis() < deadline) {
|
||||
try {
|
||||
process.exitValue();
|
||||
return true;
|
||||
} catch (IllegalThreadStateException stillRunning) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
}
|
||||
try {
|
||||
process.exitValue();
|
||||
return true;
|
||||
} catch (IllegalThreadStateException stillRunning) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void stopEverythingLocked(String logMessage) {
|
||||
if (stopping) return;
|
||||
stopping = true;
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
@@ -127,6 +128,7 @@ public class LogActivity extends Activity {
|
||||
});
|
||||
|
||||
setContentView(root);
|
||||
applyInsets(root, dp(16), dp(14), dp(16), dp(12));
|
||||
}
|
||||
|
||||
private void appendLogLine(String line) {
|
||||
@@ -177,4 +179,27 @@ public class LogActivity extends Activity {
|
||||
private int dp(int value) {
|
||||
return Math.round(value * getResources().getDisplayMetrics().density);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the root by the system bar insets. Required from API 35, where the
|
||||
* activity is laid out edge to edge and would otherwise draw under the
|
||||
* status and navigation bars.
|
||||
*/
|
||||
private void applyInsets(final View root, final int l, final int t, final int r, final int b) {
|
||||
root.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
int top, bottom, left, right;
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
android.graphics.Insets bars = insets.getInsets(WindowInsets.Type.systemBars());
|
||||
top = bars.top; bottom = bars.bottom; left = bars.left; right = bars.right;
|
||||
} else {
|
||||
top = insets.getSystemWindowInsetTop();
|
||||
bottom = insets.getSystemWindowInsetBottom();
|
||||
left = insets.getSystemWindowInsetLeft();
|
||||
right = insets.getSystemWindowInsetRight();
|
||||
}
|
||||
v.setPadding(l + left, t + top, r + right, b + bottom);
|
||||
return insets;
|
||||
});
|
||||
root.requestApplyInsets();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -28,6 +29,7 @@ import android.widget.Toast;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
private static final int VPN_REQUEST = 100;
|
||||
private static final int NOTIF_REQUEST = 101;
|
||||
private static final String PREFS = "dragontcp";
|
||||
|
||||
private static final int BATCH_LIMIT = 256;
|
||||
@@ -86,6 +88,7 @@ public class MainActivity extends Activity {
|
||||
forceDarkSystemUi();
|
||||
buildUi();
|
||||
loadSettings();
|
||||
ensureNotificationPermission();
|
||||
updateBatchHint();
|
||||
}
|
||||
|
||||
@@ -93,7 +96,15 @@ public class MainActivity extends Activity {
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
if (!receiverRegistered) {
|
||||
registerReceiver(stateReceiver, new IntentFilter(DragonService.ACTION_STATE));
|
||||
// From API 33 the export flag is mandatory. This receiver only ever
|
||||
// hears DragonService's own package-scoped broadcast, so it must be
|
||||
// NOT_EXPORTED; omitting the flag throws SecurityException.
|
||||
IntentFilter filter = new IntentFilter(DragonService.ACTION_STATE);
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
registerReceiver(stateReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
|
||||
} else {
|
||||
registerReceiver(stateReceiver, filter);
|
||||
}
|
||||
receiverRegistered = true;
|
||||
}
|
||||
updateConnectionUi(DragonService.isActive(), DragonService.currentStatus());
|
||||
@@ -110,15 +121,59 @@ public class MainActivity extends Activity {
|
||||
|
||||
private void forceDarkSystemUi() {
|
||||
Window w = getWindow();
|
||||
w.setStatusBarColor(BG);
|
||||
w.setNavigationBarColor(Color.rgb(7, 10, 14));
|
||||
// setStatusBarColor / setNavigationBarColor are no-ops once the app
|
||||
// targets API 35+, where every activity is laid out edge to edge. The
|
||||
// window background supplies the colour instead and applyInsets() keeps
|
||||
// content clear of the system bars.
|
||||
if (Build.VERSION.SDK_INT < 35) {
|
||||
w.setStatusBarColor(BG);
|
||||
w.setNavigationBarColor(Color.rgb(7, 10, 14));
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 26) w.getDecorView().setSystemUiVisibility(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the root view by the system bar insets. Required from API 35: the
|
||||
* activity draws edge to edge, so without this the header sits under the
|
||||
* status bar and the buttons under the navigation bar.
|
||||
*/
|
||||
private void applyInsets(final View root, final int l, final int t, final int r, final int b) {
|
||||
root.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
int top, bottom, left, right;
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
android.graphics.Insets bars =
|
||||
insets.getInsets(WindowInsets.Type.systemBars() | WindowInsets.Type.ime());
|
||||
top = bars.top; bottom = bars.bottom; left = bars.left; right = bars.right;
|
||||
} else {
|
||||
top = insets.getSystemWindowInsetTop();
|
||||
bottom = insets.getSystemWindowInsetBottom();
|
||||
left = insets.getSystemWindowInsetLeft();
|
||||
right = insets.getSystemWindowInsetRight();
|
||||
}
|
||||
v.setPadding(l + left, t + top, r + right, b + bottom);
|
||||
return insets;
|
||||
});
|
||||
root.requestApplyInsets();
|
||||
}
|
||||
|
||||
/** From API 33 the ongoing VPN notification is hidden without this grant. */
|
||||
private void ensureNotificationPermission() {
|
||||
if (Build.VERSION.SDK_INT < 33) return;
|
||||
if (checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS)
|
||||
== android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
requestPermissions(new String[]{ android.Manifest.permission.POST_NOTIFICATIONS }, NOTIF_REQUEST);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void buildUi() {
|
||||
LinearLayout root = new LinearLayout(this);
|
||||
root.setOrientation(LinearLayout.VERTICAL);
|
||||
root.setBackgroundColor(BG);
|
||||
// Base padding; applyInsets() adds the system bar insets on top.
|
||||
root.setPadding(dp(16), dp(14), dp(16), dp(12));
|
||||
|
||||
LinearLayout header = new LinearLayout(this);
|
||||
@@ -274,6 +329,7 @@ public class MainActivity extends Activity {
|
||||
logsButton.setOnClickListener(v -> startActivity(new Intent(this, LogActivity.class)));
|
||||
|
||||
setContentView(root);
|
||||
applyInsets(root, dp(16), dp(14), dp(16), dp(12));
|
||||
updateConnectionUi(false, "DISCONNECTED");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user