android: VPN notification as in the Final 2026 shade: protected title, pause and change actions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DenozordecandClaude Opus 5.5 committed 2026-10-12 10:12:41 +07:00
1 parent 6652970925
commit db6c806d58
5 files changed
+53 -2

No files matched your search

@@ -734,6 +734,12 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
/** /**
* Build a notification matching the current state * Build a notification matching the current state
*/ */
/** Whether «RU sites direct» is on (any mode). */
private static boolean isRuSplitOn(Context context)
{
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(Constants.PREF_RUSPLIT_GEOIP_ENABLED, false);
}
private Notification buildNotification(boolean publicVersion) private Notification buildNotification(boolean publicVersion)
{ {
/* the state service may not be bound yet when startForeground() is /* the state service may not be bound yet when startForeground() is
@@ -818,7 +824,14 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
break; break;
} }
} }
builder.setContentTitle(getString(s)); if (state == State.CONNECTED && error == ErrorState.NO_ERROR && !publicVersion && profile != null)
{ /* «Protected · Amsterdam» like the mockup shade */
builder.setContentTitle(getString(R.string.notif_protected, name));
}
else
{
builder.setContentTitle(getString(s));
}
int flags = PendingIntent.FLAG_UPDATE_CURRENT; int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
@@ -827,6 +840,17 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
} }
if (!publicVersion) if (!publicVersion)
{ {
if (state == State.CONNECTED && error == ErrorState.NO_ERROR && profile != null)
{ /* «Pause 15 min» and «Change» as on the mockup shade */
Intent pause = new Intent(getApplicationContext(), PauseReceiver.class).setAction(PauseManager.ACTION_PAUSE);
builder.addAction(R.drawable.ic_notification_connecting, getString(R.string.notif_pause),
PendingIntent.getBroadcast(getApplicationContext(), 1, pause, flags));
Intent change = new Intent(getApplicationContext(), MainActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra(MainActivity.EXTRA_OPEN_SERVERS, true);
builder.addAction(R.drawable.ic_notification, getString(R.string.notif_change),
PendingIntent.getActivity(getApplicationContext(), 2, change, flags));
}
if (add_action) if (add_action)
{ {
Intent intent = new Intent(getApplicationContext(), VpnProfileControlActivity.class); Intent intent = new Intent(getApplicationContext(), VpnProfileControlActivity.class);
@@ -837,7 +861,7 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
} }
if (error == ErrorState.NO_ERROR) if (error == ErrorState.NO_ERROR)
{ {
builder.setContentText(name); builder.setContentText(state == State.CONNECTED && isRuSplitOn(this) ? getString(R.string.notif_ru_direct) : name);
} }
builder.setPublicVersion(buildNotification(true)); builder.setPublicVersion(buildNotification(true));
} }
@@ -40,6 +40,8 @@ object PauseManager
private const val PREF_UNTIL = "pref_pause_until" private const val PREF_UNTIL = "pref_pause_until"
private const val PREF_PROFILE = "pref_pause_profile" private const val PREF_PROFILE = "pref_pause_profile"
private const val REQUEST_CODE = 45 private const val REQUEST_CODE = 45
/** «Pause 15 min» from the VPN notification */
const val ACTION_PAUSE = "org.strongswan.android.action.PAUSE_15"
/* safety net of "until the network changes" */ /* safety net of "until the network changes" */
private const val NETWORK_PAUSE_MAX_MS = 12L * 60 * 60 * 1000 private const val NETWORK_PAUSE_MAX_MS = 12L * 60 * 60 * 1000
@@ -329,6 +331,13 @@ class PauseReceiver : BroadcastReceiver()
{ {
override fun onReceive(context: Context, intent: Intent?) override fun onReceive(context: Context, intent: Intent?)
{ {
if (intent?.action == PauseManager.ACTION_PAUSE)
{
val service = VpnStateService.getLiveInstance() ?: return
val profile = service.profile ?: return
PauseManager.pause(context, service, profile.getUUID().toString(), 15)
return
}
PauseManager.onAlarm(context) PauseManager.onAlarm(context)
} }
} }
@@ -47,6 +47,11 @@ public class MainActivity extends AppCompatActivity
*/ */
public static final String EXTRA_ADD_SERVER = "org.strongswan.android.extra.ADD_SERVER"; public static final String EXTRA_ADD_SERVER = "org.strongswan.android.extra.ADD_SERVER";
/**
* Set as an intent extra to open the Servers tab (the «Change» action of the notification)
*/
public static final String EXTRA_OPEN_SERVERS = "org.strongswan.android.extra.OPEN_SERVERS";
/** /**
* Use "bring your own device" (BYOD) features * Use "bring your own device" (BYOD) features
*/ */
@@ -111,5 +116,10 @@ public class MainActivity extends AppCompatActivity
intent.removeExtra(EXTRA_ADD_SERVER); intent.removeExtra(EXTRA_ADD_SERVER);
ShxNavigation.INSTANCE.requestAddServer(); ShxNavigation.INSTANCE.requestAddServer();
} }
if (intent != null && intent.getBooleanExtra(EXTRA_OPEN_SERVERS, false))
{
intent.removeExtra(EXTRA_OPEN_SERVERS);
ShxNavigation.INSTANCE.request(ShxTab.PROFILES);
}
} }
} }
@@ -1009,4 +1009,8 @@
<string name="perm_tag_optional">по желанию</string> <string name="perm_tag_optional">по желанию</string>
<string name="perm_allow">Разрешить</string> <string name="perm_allow">Разрешить</string>
<string name="perm_done">Готово</string> <string name="perm_done">Готово</string>
<string name="notif_protected">Защищено · %1$s</string>
<string name="notif_pause">Пауза 15 м</string>
<string name="notif_change">Сменить</string>
<string name="notif_ru_direct">RU-сайты идут напрямую</string>
</resources> </resources>
@@ -994,4 +994,8 @@
<string name="perm_tag_optional">optional</string> <string name="perm_tag_optional">optional</string>
<string name="perm_allow">Allow</string> <string name="perm_allow">Allow</string>
<string name="perm_done">Done</string> <string name="perm_done">Done</string>
<string name="notif_protected">Protected · %1$s</string>
<string name="notif_pause">Pause 15 min</string>
<string name="notif_change">Change</string>
<string name="notif_ru_direct">RU sites go direct</string>
</resources> </resources>