This commit is contained in:
2026-08-16 03:57:11 -03:00
parent 8486e54329
commit bb8b966a75
5 changed files with 74 additions and 35 deletions
+17 -22
View File
@@ -194,34 +194,29 @@ FreeProxy project. See `THIRD_PARTY_NOTICES.md` and
- ARM64 Android DragonTCP core build: PASS.
- APK resource/DEX/native packaging: PASS.
- APK signature verification (v3): PASS.
- Supplied APK uses the same signing certificate as the previous Lite/v7 APK and has versionCode 9, so it can be installed as an in-place update.
- Supplied APK uses the same signing certificate as the previous Lite/v7 APK and has versionCode 10, so it can be installed as an in-place update.
A physical Android device is still required to validate the final VpnService
path against a real mobile network.
## v9 dark UI update
## v10 split UI update
This release changes only the Android UI/service state handling. The embedded
DragonTCP Go transport core is byte-for-byte identical to the previous Lite
release.
This release changes only the Android UI. The embedded DragonTCP transport
core and the Lite server are unchanged from the working Lite release.
UI changes:
- permanent dark theme independent of the Android system theme
- fixed header with CONNECTED / CONNECTING / STOPPING / DISCONNECTED state
- connection and transport settings are grouped into compact dark cards
- the settings area and Live Log have independent scrolling regions
- Live Log appends new lines in-place and no longer calls
`fullScroll(FOCUS_DOWN)`, so log updates do not move the settings screen
- automatic log following happens only while the user is already near the
bottom; scrolling upward pauses auto-follow
- CONNECT is immediately disabled/greyed while connecting or connected
- STOP is enabled only while DragonTCP is active
- the service independently rejects duplicate CONNECT commands, so a double
tap cannot restart a working tunnel
- connection state is broadcast to the Activity, so buttons and the status
chip update without rebuilding the screen
- Live Log is a true sibling pane below the settings pane; it is never drawn
over the settings.
- The settings pane is explicitly clipped to its own region.
- The settings scrollbar is hidden, so no scrollbar can appear behind the log.
- Live Log keeps its own internal scroll area and receives appended lines
without rebuilding the Activity.
- A visible divider separates settings from Live Log.
- CONNECT remains disabled while connecting/connected and STOP remains state-aware.
- The visible XOR wording was removed from the Android UI. Transport behavior
itself is unchanged.
- The Activity explicitly uses `adjustResize` when the keyboard opens.
The supplied APK is versionCode 9 / versionName `9.0-lite-ui` and is signed
with the same DragonTCP VPN development certificate used by the preceding
Lite APK, allowing an in-place update.
The APK is versionCode 10 / versionName `10.0-lite-split-ui` and is signed with
the same certificate as the previous Lite UI build.
+4 -3
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dragontcp.client"
android:versionCode="9"
android:versionName="9.0-lite-ui">
android:versionCode="10"
android:versionName="10.0-lite-split-ui">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
<uses-permission android:name="android.permission.INTERNET" />
@@ -19,7 +19,8 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="portrait">
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -19,6 +19,7 @@ import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
@@ -121,8 +122,10 @@ public class MainActivity extends Activity {
root.setOrientation(LinearLayout.VERTICAL);
root.setBackgroundColor(BG);
root.setPadding(dp(16), dp(14), dp(16), dp(12));
root.setClipChildren(true);
root.setClipToPadding(true);
// Fixed header: never moves when logs are appended.
// Header is outside both scrolling regions.
LinearLayout header = new LinearLayout(this);
header.setOrientation(LinearLayout.HORIZONTAL);
header.setGravity(Gravity.CENTER_VERTICAL);
@@ -131,7 +134,7 @@ public class MainActivity extends Activity {
LinearLayout heading = new LinearLayout(this);
heading.setOrientation(LinearLayout.VERTICAL);
TextView title = text("DragonTCP Lite", 25, TEXT, true);
TextView subtitle = text("Adaptive XOR tunnel over TCP/53", 12, MUTED, false);
TextView subtitle = text("Adaptive tunnel over TCP/53", 12, MUTED, false);
subtitle.setPadding(0, dp(2), 0, 0);
heading.addView(title);
heading.addView(subtitle);
@@ -144,11 +147,30 @@ public class MainActivity extends Activity {
header.addView(statusChip);
root.addView(header);
// Only the settings area scrolls. The log panel below has its own independent scroll.
// The remaining screen is an explicit vertical split. The settings pane and
// Live Log pane are siblings; neither is drawn over the other.
LinearLayout split = new LinearLayout(this);
split.setOrientation(LinearLayout.VERTICAL);
split.setClipChildren(true);
split.setClipToPadding(true);
root.addView(split, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
0,
1f
));
FrameLayout settingsPane = new FrameLayout(this);
settingsPane.setBackgroundColor(BG);
settingsPane.setClipChildren(true);
settingsPane.setClipToPadding(true);
ScrollView settingsScroll = new ScrollView(this);
settingsScroll.setFillViewport(false);
settingsScroll.setClipToPadding(false);
settingsScroll.setClipToPadding(true);
settingsScroll.setClipChildren(true);
settingsScroll.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS);
// Avoid a scrollbar visually continuing into the separate log pane.
settingsScroll.setVerticalScrollBarEnabled(false);
LinearLayout settings = new LinearLayout(this);
settings.setOrientation(LinearLayout.VERTICAL);
@@ -157,6 +179,10 @@ public class MainActivity extends Activity {
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
settingsPane.addView(settingsScroll, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
LinearLayout connectionCard = card("CONNECTION");
server = addField(connectionCard, "Server", "Server IP or hostname", "", false, false);
@@ -177,7 +203,7 @@ public class MainActivity extends Activity {
timeout = addFieldToRow(timing, "Timeout (s)", "2", "2", true, false, 0.42f);
transportCard.addView(timing);
TextView fixed = text("1 poller • Start = Max chunk • XOR 0xAD always on", 11, MUTED, false);
TextView fixed = text("1 poller • Start = Max chunk", 11, MUTED, false);
fixed.setPadding(dp(2), dp(6), dp(2), dp(2));
transportCard.addView(fixed);
settings.addView(transportCard, cardParams());
@@ -202,15 +228,28 @@ public class MainActivity extends Activity {
note.setPadding(dp(4), dp(2), dp(4), dp(6));
settings.addView(note);
root.addView(settingsScroll, new LinearLayout.LayoutParams(
// Give settings the upper portion of the available body. This FrameLayout
// clips its ScrollView, making it impossible for settings to draw behind logs.
split.addView(settingsPane, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
0,
1f
0.58f
));
// Fixed log panel. New lines can never change the position/size of the settings area.
View divider = new View(this);
divider.setBackgroundColor(BORDER);
LinearLayout.LayoutParams dividerParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dp(1)
);
dividerParams.setMargins(dp(6), dp(7), dp(6), dp(7));
split.addView(divider, dividerParams);
// Live Log is a true sibling below settings, not an overlay.
LinearLayout logPanel = new LinearLayout(this);
logPanel.setOrientation(LinearLayout.VERTICAL);
logPanel.setClipChildren(true);
logPanel.setClipToPadding(true);
logPanel.setBackground(roundRect(CARD, 16, BORDER, 1));
logPanel.setPadding(dp(10), dp(8), dp(10), dp(10));
@@ -225,6 +264,8 @@ public class MainActivity extends Activity {
logScroll = new ScrollView(this);
logScroll.setFillViewport(true);
logScroll.setFocusable(false);
logScroll.setClipChildren(true);
logScroll.setClipToPadding(true);
logScroll.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS);
logScroll.setBackground(roundRect(LOG_BG, 11, Color.rgb(30, 38, 49), 1));
@@ -244,9 +285,11 @@ public class MainActivity extends Activity {
0,
1f
));
root.addView(logPanel, new LinearLayout.LayoutParams(
split.addView(logPanel, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dp(238)
0,
0.42f
));
clear.setOnClickListener(v -> {
Binary file not shown.
Binary file not shown.