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