Merge branch 'android-passwords'

Adds support to import passwords via managed configuration and profile
files. Also fixes several deprecation warnings.

Closes strongswan/strongswan#2589
Closes strongswan/strongswan#2642
Closes strongswan/strongswan#2643
This commit is contained in:
Tobias Brunner
2025-02-20 11:08:29 +01:00
45 changed files with 320 additions and 153 deletions
+3 -3
View File
@@ -9,8 +9,8 @@ android {
minSdkVersion 21
targetSdkVersion 34
versionCode 84
versionName "2.5.2"
versionCode 87
versionName "2.5.3"
externalNativeBuild {
ndkBuild {
@@ -19,7 +19,7 @@ android {
}
}
ndkVersion "26.1.10909125"
ndkVersion "27.2.12479018"
externalNativeBuild {
ndkBuild {
@@ -37,6 +37,7 @@
android:label="@string/app_name"
android:theme="@style/ApplicationTheme"
android:networkSecurityConfig="@xml/network_security_config"
android:enableOnBackInvokedCallback="true"
android:allowBackup="false" >
<activity
android:name=".ui.MainActivity"
@@ -121,6 +121,7 @@ public class ManagedConfiguration
return Arrays.asList(bundles);
}
@SuppressWarnings("deprecation")
@NonNull
private static List<Bundle> getBundleArrayListCompat(final Bundle bundle, final String key)
{
@@ -68,9 +68,9 @@ public class ManagedVpnProfile extends VpnProfile
setMTU(getInt(bundle, VpnProfileDataSource.KEY_MTU, Constants.MTU_MIN, Constants.MTU_MAX));
setNATKeepAlive(getInt(bundle, VpnProfileDataSource.KEY_NAT_KEEPALIVE, Constants.NAT_KEEPALIVE_MIN, Constants.NAT_KEEPALIVE_MAX));
setIkeProposal(bundle.getString(VpnProfileDataSource.KEY_IKE_PROPOSAL));
setEspProposal(bundle.getString(VpnProfileDataSource.KEY_ESP_PROPOSAL));
setDnsServers(bundle.getString(VpnProfileDataSource.KEY_DNS_SERVERS));
setIkeProposal(getString(bundle, VpnProfileDataSource.KEY_IKE_PROPOSAL));
setEspProposal(getString(bundle, VpnProfileDataSource.KEY_ESP_PROPOSAL));
setDnsServers(getString(bundle, VpnProfileDataSource.KEY_DNS_SERVERS));
flags = addPositiveFlag(flags, bundle, KEY_TRANSPORT_IPV6_FLAG, VpnProfile.FLAGS_IPv6_TRANSPORT);
final Bundle splitTunneling = bundle.getBundle(VpnProfileDataSource.KEY_SPLIT_TUNNELING);
@@ -79,8 +79,8 @@ public class ManagedVpnProfile extends VpnProfile
splitFlags = addPositiveFlag(splitFlags, splitTunneling, KEY_SPLIT_TUNNELLING_BLOCK_IPV4_FLAG, VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4);
splitFlags = addPositiveFlag(splitFlags, splitTunneling, KEY_SPLIT_TUNNELLING_BLOCK_IPV6_FLAG, VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6);
setExcludedSubnets(splitTunneling.getString(VpnProfileDataSource.KEY_EXCLUDED_SUBNETS));
setIncludedSubnets(splitTunneling.getString(VpnProfileDataSource.KEY_INCLUDED_SUBNETS));
setExcludedSubnets(getString(splitTunneling, VpnProfileDataSource.KEY_EXCLUDED_SUBNETS));
setIncludedSubnets(getString(splitTunneling, VpnProfileDataSource.KEY_INCLUDED_SUBNETS));
}
setSplitTunneling(splitFlags);
@@ -110,7 +110,7 @@ public class ManagedVpnProfile extends VpnProfile
setGateway(remote.getString(VpnProfileDataSource.KEY_GATEWAY));
setPort(getInt(remote, VpnProfileDataSource.KEY_PORT, 1, 65_535));
setRemoteId(remote.getString(VpnProfileDataSource.KEY_REMOTE_ID));
setRemoteId(getString(remote, VpnProfileDataSource.KEY_REMOTE_ID));
final String certificateData = remote.getString(VpnProfileDataSource.KEY_CERTIFICATE);
if (!TextUtils.isEmpty(certificateData))
@@ -133,8 +133,9 @@ public class ManagedVpnProfile extends VpnProfile
return flags;
}
setLocalId(local.getString(VpnProfileDataSource.KEY_LOCAL_ID));
setUsername(local.getString(VpnProfileDataSource.KEY_USERNAME));
setLocalId(getString(local, VpnProfileDataSource.KEY_LOCAL_ID));
setUsername(getString(local, VpnProfileDataSource.KEY_USERNAME));
setPassword(getString(local, VpnProfileDataSource.KEY_PASSWORD));
final String userCertificateData = local.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE);
final String userCertificatePassword = local.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE_PASSWORD, "");
@@ -154,6 +155,12 @@ public class ManagedVpnProfile extends VpnProfile
return value < min || value > max ? null : value;
}
private static String getString(final Bundle bundle, final String key)
{
final String value = bundle.getString(key);
return TextUtils.isEmpty(value) ? null : value;
}
private static int addPositiveFlag(int flags, Bundle bundle, String key, int flag)
{
if (bundle.getBoolean(key))
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2025 Tobias Brunner
* Copyright (C) 2023 Relution GmbH
*
* Copyright (C) secunet Security Networks AG
@@ -75,17 +76,14 @@ public class VpnProfileManagedDataSource implements VpnProfileDataSource
@Override
public boolean updateVpnProfile(VpnProfile profile)
{
final VpnProfile existingProfile = getVpnProfile(profile.getUUID());
if (existingProfile == null)
final VpnProfile managedProfile = mManagedConfigurationService.getManagedProfiles().get(profile.getUUID().toString());
if (managedProfile == null)
{
return false;
}
final String password = profile.getPassword();
existingProfile.setPassword(password);
final SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(profile.getUUID().toString(), password);
editor.putString(profile.getUUID().toString(), profile.getPassword());
return editor.commit();
}
@@ -95,10 +93,28 @@ public class VpnProfileManagedDataSource implements VpnProfileDataSource
return false;
}
/**
* Clone and prepare the given managed profile before handing it out.
* @param managedProfile profile to prepare
*/
private VpnProfile prepareVpnProfile(VpnProfile managedProfile)
{
final String password = mSharedPreferences.getString(managedProfile.getUUID().toString(), managedProfile.getPassword());
final VpnProfile vpnProfile = managedProfile.clone();
vpnProfile.setPassword(password);
vpnProfile.setDataSource(this);
return vpnProfile;
}
@Override
public VpnProfile getVpnProfile(UUID uuid)
{
return mManagedConfigurationService.getManagedProfiles().get(uuid.toString());
final VpnProfile managedProfile = mManagedConfigurationService.getManagedProfiles().get(uuid.toString());
if (managedProfile != null)
{
return prepareVpnProfile(managedProfile);
}
return null;
}
@Override
@@ -106,12 +122,9 @@ public class VpnProfileManagedDataSource implements VpnProfileDataSource
{
final Map<String, ManagedVpnProfile> managedVpnProfiles = mManagedConfigurationService.getManagedProfiles();
final List<VpnProfile> vpnProfiles = new ArrayList<>();
for (final VpnProfile vpnProfile : managedVpnProfiles.values())
for (final VpnProfile managedProfile : managedVpnProfiles.values())
{
final String password = mSharedPreferences.getString(vpnProfile.getUUID().toString(), vpnProfile.getPassword());
vpnProfile.setPassword(password);
vpnProfile.setDataSource(this);
vpnProfiles.add(vpnProfile);
vpnProfiles.add(prepareVpnProfile(managedProfile));
}
return vpnProfiles;
}
@@ -399,11 +399,24 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
public void run()
{
mShowNotification = false;
stopForeground(true);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
{
stopForegroundCompat();
}
else
{
stopForeground(STOP_FOREGROUND_REMOVE);
}
}
});
}
@SuppressWarnings("deprecation")
private void stopForegroundCompat()
{
stopForeground(true);
}
/**
* Create a notification channel for Android 8+
*/
@@ -16,6 +16,7 @@
package org.strongswan.android.ui;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -58,7 +59,14 @@ public class RemediationInstructionFragment extends ListFragment
if (savedInstanceState != null)
{
mInstruction = savedInstanceState.getParcelable(ARG_REMEDIATION_INSTRUCTION);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
{
mInstruction = getInstructionCompat(savedInstanceState);
}
else
{
mInstruction = savedInstanceState.getParcelable(ARG_REMEDIATION_INSTRUCTION, RemediationInstruction.class);
}
}
/* show dividers only between list items */
getListView().setHeaderDividersEnabled(false);
@@ -85,7 +93,14 @@ public class RemediationInstructionFragment extends ListFragment
Bundle args = getArguments();
if (args != null)
{
mInstruction = args.getParcelable(ARG_REMEDIATION_INSTRUCTION);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
{
mInstruction = getInstructionCompat(args);
}
else
{
mInstruction = args.getParcelable(ARG_REMEDIATION_INSTRUCTION, RemediationInstruction.class);
}
}
updateView(mInstruction);
}
@@ -117,4 +132,10 @@ public class RemediationInstructionFragment extends ListFragment
setListAdapter(null);
}
}
@SuppressWarnings("deprecation")
private static RemediationInstruction getInstructionCompat(Bundle bundle)
{
return bundle.getParcelable(ARG_REMEDIATION_INSTRUCTION);
}
}
@@ -43,7 +43,16 @@ public class RemediationInstructionsActivity extends AppCompatActivity implement
if (frag != null)
{ /* two-pane layout, update fragment */
Bundle extras = getIntent().getExtras();
ArrayList<RemediationInstruction> list = extras.getParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS);
ArrayList<RemediationInstruction> list = null;
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU)
{
list = RemediationInstructionsFragment.getInstructionsCompat(extras);
}
else
{
list = extras.getParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS,
RemediationInstruction.class);
}
frag.updateView(list);
}
else
@@ -17,6 +17,7 @@
package org.strongswan.android.ui;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
@@ -55,7 +56,14 @@ public class RemediationInstructionsFragment extends ListFragment
if (savedInstanceState != null)
{
mInstructions = savedInstanceState.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
{
mInstructions = getInstructionsCompat(savedInstanceState);
}
else
{
mInstructions = savedInstanceState.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS, RemediationInstruction.class);
}
mCurrentPosition = savedInstanceState.getInt(KEY_POSITION);
}
}
@@ -93,7 +101,14 @@ public class RemediationInstructionsFragment extends ListFragment
Bundle args = getArguments();
if (mInstructions == null && args != null)
{
mInstructions = args.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
{
mInstructions = getInstructionsCompat(args);
}
else
{
mInstructions = args.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS, RemediationInstruction.class);
}
}
updateView(mInstructions);
@@ -123,4 +138,10 @@ public class RemediationInstructionsFragment extends ListFragment
mInstructions = instructions;
mAdapter.setData(mInstructions);
}
@SuppressWarnings("deprecation")
public static ArrayList<RemediationInstruction> getInstructionsCompat(Bundle bundle)
{
return bundle.getParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS);
}
}
@@ -22,6 +22,7 @@ import android.view.MenuItem;
import org.strongswan.android.data.VpnProfileDataSource;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
@@ -40,6 +41,16 @@ public class SelectedApplicationsActivity extends AppCompatActivity
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true)
{
@Override
public void handleOnBackPressed()
{
prepareResult();
finish();
}
});
FragmentManager fm = getSupportFragmentManager();
mApps = (SelectedApplicationsListFragment)fm.findFragmentByTag(LIST_TAG);
if (mApps == null)
@@ -62,13 +73,6 @@ public class SelectedApplicationsActivity extends AppCompatActivity
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed()
{
prepareResult();
super.onBackPressed();
}
private void prepareResult()
{
Intent data = new Intent();
@@ -44,12 +44,13 @@ import java.util.TreeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView;
import androidx.core.view.MenuProvider;
import androidx.fragment.app.ListFragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.AsyncTaskLoader;
import androidx.loader.content.Loader;
public class SelectedApplicationsListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Pair<List<SelectedApplicationEntry>, List<String>>>, SearchView.OnQueryTextListener
public class SelectedApplicationsListFragment extends ListFragment implements MenuProvider, LoaderManager.LoaderCallbacks<Pair<List<SelectedApplicationEntry>, List<String>>>, SearchView.OnQueryTextListener
{
private SelectedApplicationsAdapter mAdapter;
private SortedSet<String> mSelection;
@@ -58,7 +59,7 @@ public class SelectedApplicationsListFragment extends ListFragment implements Lo
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
requireActivity().addMenuProvider(this, getViewLifecycleOwner());
final boolean readOnly = getActivity().getIntent().getBooleanExtra(VpnProfileDataSource.KEY_READ_ONLY, false);
getListView().setChoiceMode(readOnly ? ListView.CHOICE_MODE_NONE : ListView.CHOICE_MODE_MULTIPLE);
@@ -134,17 +135,21 @@ public class SelectedApplicationsListFragment extends ListFragment implements Lo
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
{
MenuItem item = menu.add(R.string.search);
item.setIcon(android.R.drawable.ic_menu_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
SearchView sv = new SearchView(getActivity());
sv.setOnQueryTextListener(this);
item.setActionView(sv);
}
super.onCreateOptionsMenu(menu, inflater);
@Override
public boolean onMenuItemSelected(@NonNull MenuItem menuItem)
{
return false;
}
@Override
@@ -21,6 +21,7 @@ import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
@@ -191,7 +192,14 @@ public class TrustedCertificateImportActivity extends AppCompatActivity
{
final X509Certificate certificate;
certificate = (X509Certificate)getArguments().getSerializable(VpnProfileDataSource.KEY_CERTIFICATE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
{
certificate = getCertificateCompat(getArguments());
}
else
{
certificate = getArguments().getSerializable(VpnProfileDataSource.KEY_CERTIFICATE, X509Certificate.class);
}
return new AlertDialog.Builder(getActivity())
.setIcon(R.mipmap.ic_app)
@@ -230,5 +238,11 @@ public class TrustedCertificateImportActivity extends AppCompatActivity
{
getActivity().finish();
}
@SuppressWarnings("deprecation")
private static X509Certificate getCertificateCompat(Bundle bundle)
{
return (X509Certificate)bundle.getSerializable(VpnProfileDataSource.KEY_CERTIFICATE);
}
}
}
@@ -17,6 +17,7 @@
package org.strongswan.android.ui;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
@@ -44,13 +45,15 @@ import java.util.Map.Entry;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.MenuProvider;
import androidx.fragment.app.ListFragment;
import androidx.lifecycle.Lifecycle;
import androidx.loader.app.LoaderManager;
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.AsyncTaskLoader;
import androidx.loader.content.Loader;
public class TrustedCertificateListFragment extends ListFragment implements LoaderCallbacks<List<TrustedCertificateEntry>>, OnQueryTextListener
public class TrustedCertificateListFragment extends ListFragment implements MenuProvider, LoaderCallbacks<List<TrustedCertificateEntry>>, OnQueryTextListener
{
public static final String EXTRA_CERTIFICATE_SOURCE = "certificate_source";
private OnTrustedCertificateSelectedListener mListener;
@@ -69,7 +72,7 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
requireActivity().addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED);
setEmptyText(getString(R.string.no_certificates));
@@ -81,7 +84,14 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
Bundle arguments = getArguments();
if (arguments != null)
{
mSource = (TrustedCertificateSource)arguments.getSerializable(EXTRA_CERTIFICATE_SOURCE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
{
mSource = getCertificateSourceCompat(arguments);
}
else
{
mSource = arguments.getSerializable(EXTRA_CERTIFICATE_SOURCE, TrustedCertificateSource.class);
}
}
LoaderManager.getInstance(this).initLoader(0, null, this);
@@ -105,17 +115,23 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
{
MenuItem item = menu.add(R.string.search);
item.setIcon(android.R.drawable.ic_menu_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
SearchView sv = new SearchView(getActivity());
sv.setOnQueryTextListener(this);
item.setActionView(sv);
}
@Override
public boolean onMenuItemSelected(@NonNull MenuItem menuItem)
{
return false;
}
@Override
public boolean onQueryTextSubmit(String query)
{ /* already handled when the text changes */
@@ -260,4 +276,10 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
}
}
}
@SuppressWarnings("deprecation")
private static TrustedCertificateSource getCertificateSourceCompat(Bundle bundle)
{
return (TrustedCertificateSource)bundle.getSerializable(EXTRA_CERTIFICATE_SOURCE);
}
}
@@ -21,6 +21,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.security.KeyChain;
import android.security.KeyChainAliasCallback;
@@ -98,6 +99,7 @@ public class VpnProfileImportActivity extends AppCompatActivity
private boolean mHideImport;
private androidx.core.widget.ContentLoadingProgressBar mProgressBar;
private TextView mExistsWarning;
private TextView mSharedSecretWarning;
private ViewGroup mBasicDataGroup;
private TextView mName;
private TextView mGateway;
@@ -139,6 +141,19 @@ public class VpnProfileImportActivity extends AppCompatActivity
{
@Override
public Loader<ProfileLoadResult> onCreateLoader(int id, Bundle args)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
{
return createCompat(args);
}
else
{
return new ProfileLoader(VpnProfileImportActivity.this, args.getParcelable(PROFILE_URI, Uri.class));
}
}
@SuppressWarnings("deprecation")
public Loader<ProfileLoadResult> createCompat(Bundle args)
{
return new ProfileLoader(VpnProfileImportActivity.this, args.getParcelable(PROFILE_URI));
}
@@ -192,6 +207,7 @@ public class VpnProfileImportActivity extends AppCompatActivity
mProgressBar = findViewById(R.id.progress_bar);
mExistsWarning = findViewById(R.id.exists_warning);
mSharedSecretWarning = findViewById(R.id.shared_secret_warning);
mBasicDataGroup = findViewById(R.id.basic_data_group);
mName = findViewById(R.id.name);
mGateway = findViewById(R.id.gateway);
@@ -210,6 +226,7 @@ public class VpnProfileImportActivity extends AppCompatActivity
mRemoteCert = findViewById(R.id.remote_certificate);
mExistsWarning.setVisibility(View.GONE);
mSharedSecretWarning.setVisibility(View.GONE);
mBasicDataGroup.setVisibility(View.GONE);
mUsernamePassword.setVisibility(View.GONE);
mUserCertificate.setVisibility(View.GONE);
@@ -386,10 +403,16 @@ public class VpnProfileImportActivity extends AppCompatActivity
if (mProfile.getVpnType().has(VpnTypeFeature.USER_PASS))
{
mUsername.setText(mProfile.getUsername());
if (mProfile.getUsername() != null && !mProfile.getUsername().isEmpty())
if (!TextUtils.isEmpty(mProfile.getUsername()))
{
mUsername.setEnabled(false);
}
mPassword.setText(mProfile.getPassword());
if (!TextUtils.isEmpty(mProfile.getPassword()))
{
mPassword.setEnabled(false);
mSharedSecretWarning.setVisibility(View.VISIBLE);
}
}
mUserCertificate.setVisibility(mProfile.getVpnType().has(VpnTypeFeature.CERTIFICATE) ? View.VISIBLE : View.GONE);
@@ -509,6 +532,7 @@ public class VpnProfileImportActivity extends AppCompatActivity
if (type.has(VpnTypeFeature.USER_PASS))
{
profile.setUsername(local.optString("eap_id", null));
profile.setPassword(local.optString("shared_secret", null));
}
if (type.has(VpnTypeFeature.CERTIFICATE))
@@ -57,10 +57,13 @@ import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import androidx.annotation.NonNull;
import androidx.core.view.MenuProvider;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class VpnProfileListFragment extends Fragment
public class VpnProfileListFragment extends Fragment implements MenuProvider
{
private static final String SELECTED_KEY = "SELECTED";
@@ -148,6 +151,7 @@ public class VpnProfileListFragment extends Fragment
if (!mReadOnly)
{
requireActivity().addMenuProvider(this, getViewLifecycleOwner());
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mListView.setMultiChoiceModeListener(mVpnProfileSelected);
}
@@ -167,8 +171,6 @@ public class VpnProfileListFragment extends Fragment
if (!mReadOnly)
{
setHasOptionsMenu(true);
ArrayList<Integer> selected = null;
if (savedInstanceState != null)
{
@@ -218,13 +220,13 @@ public class VpnProfileListFragment extends Fragment
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
{
inflater.inflate(R.menu.profile_list, menu);
menuInflater.inflate(R.menu.profile_list, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu)
public void onPrepareMenu(@NonNull Menu menu)
{
final MenuItem addProfile = menu.findItem(R.id.add_profile);
if (addProfile != null)
@@ -236,16 +238,16 @@ public class VpnProfileListFragment extends Fragment
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
public boolean onMenuItemSelected(@NonNull MenuItem menuItem)
{
if (item.getItemId() == R.id.add_profile)
if (menuItem.getItemId() == R.id.add_profile)
{
Intent connectionIntent = new Intent(getActivity(),
VpnProfileDetailActivity.class);
startActivity(connectionIntent);
return true;
}
return super.onOptionsItemSelected(item);
return false;
}
private final OnItemClickListener mVpnProfileClicked = new OnItemClickListener()
@@ -187,7 +187,7 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
}
else
{
startActivityAndCollapse(intent);
startActivityAndCollapseCompat(intent);
}
}
else
@@ -214,10 +214,16 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
}
else
{
startActivityAndCollapse(intent);
startActivityAndCollapseCompat(intent);
}
}
@SuppressWarnings("deprecation")
private void startActivityAndCollapseCompat(Intent intent)
{
startActivityAndCollapse(intent);
}
@Override
public void stateChanged()
{
@@ -1 +1,2 @@
APP_PLATFORM := android-21
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
@@ -820,6 +820,7 @@ JNI_METHOD_P(org_strongswan_android_utils, Utils, parseInetAddressBytes, jbyteAr
host = host_create_from_string(str, 0);
if (!host)
{
library_deinit();
free(str);
return NULL;
}
@@ -1,13 +1,6 @@
# 2.5.2 #
# 2.5.3 #
- Ziel-SDK auf Android 14 erhöht
- Wegen eines Bugs in Android 14 ist eine zusätzliche Permission ist nötig, um von der Status-Kachel eine Verbindung im Hintergrund zu starten
- Fixt einen Crash beim Öffnen der Liste installierter Apps in neuen Profilen
# 2.5.1 #
- Fix für existierende Verknüpfungen und Automatisierung via Intents
# 2.5.0 #
- Unterstützung für verwaltete Konfigurationen via Enterprise Mobility Management (EMM)
- Unterstützt die Verteilung von Passwörtern in verwalteten Profilen
- Unterstützt den Import von Profil-Dateien mit Passwörtern
- Fixt einen Crash beim Ändern des Passworts von verwalteten Profilen
- Fixt einen Crash beim Importieren eines bereit existierenden Profils
@@ -1,13 +1,6 @@
# 2.5.2 #
# 2.5.3 #
- Increased target SDK to Android 14
- Due to a bug in Android 14, a new permission is necessary to start a profile in the background from the status tile
- Fix crash when listing installed apps for new profiles
# 2.5.1 #
- Fix for existing shortcuts and automation via Intents
# 2.5.0 #
- Support for managed configurations via enterprise mobility management (EMM)
- Add support for distributing passwords in managed profiles
- Add support for importing profile files with passwords
- Fix crash when editing password of managed profiles
- Fix crash when re-importing an already existing profile
@@ -30,15 +30,15 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginTop="10dp"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:text="@string/imc_state_label"
android:textColor="?android:textColorPrimary"
android:textSize="20sp" />
@@ -58,8 +58,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:text="@string/show_remediation_instructions"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
@@ -27,7 +27,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/state_background"
android:drawableStart="@android:drawable/ic_dialog_alert"
app:drawableStartCompat="@android:drawable/ic_dialog_alert"
android:drawablePadding="8dp"
android:padding="8dp"
android:text="@string/alert_text_vpn_profile_read_only"
@@ -73,7 +73,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:text="@string/profile_vpn_type_label"
android:textSize="12sp" />
@@ -140,7 +140,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
android:text="@string/profile_user_certificate_label"
android:textSize="12sp" />
@@ -153,8 +153,8 @@
android:id="@+id/install_user_certificate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:text="@string/profile_user_certificate_install" />
</LinearLayout>
@@ -162,7 +162,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:text="@string/profile_ca_label"
android:textSize="12sp" />
@@ -210,7 +210,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_marginTop="10dp"
android:text="@string/profile_advanced_label"
android:textSize="20sp" />
@@ -319,14 +319,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:text="@string/profile_cert_req_label" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_cert_req_hint"
android:textSize="12sp" />
@@ -336,14 +334,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:text="@string/profile_use_ocsp_label" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_use_ocsp_hint"
android:textSize="12sp" />
@@ -353,14 +349,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:text="@string/profile_use_crl_label" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_use_crl_hint"
android:textSize="12sp" />
@@ -370,14 +364,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:text="@string/profile_strict_revocation_label" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_strict_revocation_hint"
android:textSize="12sp" />
@@ -387,14 +379,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:text="@string/profile_rsa_pss_label" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_rsa_pss_hint"
android:textSize="12sp" />
@@ -404,14 +394,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:text="@string/profile_ipv6_transport_label" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_ipv6_transport_hint"
android:textSize="12sp" />
@@ -420,7 +408,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_split_tunneling_label"
@@ -429,7 +416,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_split_tunneling_intro"
@@ -484,7 +471,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_select_apps_label"
@@ -505,7 +491,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_proposals_label"
@@ -515,7 +500,7 @@
android:id="@+id/proposal_intro"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_proposals_intro"
@@ -558,7 +543,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="@string/profile_profile_id"
@@ -568,7 +552,6 @@
android:id="@+id/profile_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:textIsSelectable="true"
@@ -40,14 +40,27 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:drawableLeft="@android:drawable/ic_dialog_alert"
android:drawableStart="@android:drawable/ic_dialog_alert"
app:drawableStartCompat="@android:drawable/ic_dialog_alert"
android:drawablePadding="8dp"
android:textStyle="bold"
android:text="@string/profile_import_exists"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" />
<TextView
android:id="@+id/shared_secret_warning"
android:background="@drawable/state_background"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:drawableStartCompat="@android:drawable/ic_dialog_alert"
android:drawablePadding="8dp"
android:textStyle="bold"
android:text="@string/profile_import_shared_secret"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" />
<LinearLayout
android:id="@+id/basic_data_group"
android:layout_width="match_parent"
@@ -57,7 +70,6 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textSize="12sp"
android:text="@string/profile_name_label_simple" />
@@ -66,7 +78,6 @@
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary" />
@@ -75,7 +86,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textSize="12sp"
android:text="@string/profile_gateway_label" />
@@ -84,7 +94,6 @@
android:id="@+id/gateway"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary" />
@@ -93,7 +102,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textSize="12sp"
android:text="@string/profile_vpn_type_label" />
@@ -103,7 +111,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary" />
@@ -162,7 +169,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textSize="12sp"
android:text="@string/profile_user_certificate_label" />
@@ -174,8 +181,8 @@
android:id="@+id/import_user_certificate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:text="@string/profile_cert_import" />
</LinearLayout>
@@ -190,7 +197,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textSize="12sp"
android:text="@string/profile_ca_label" />
@@ -19,8 +19,8 @@
android:layout_height="match_parent"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:paddingLeft="5dp"
android:paddingRight="5dp" >
android:paddingStart="5dp"
android:paddingEnd="5dp" >
<ListView
android:id="@+id/profile_list"
@@ -33,7 +33,7 @@
<TextView android:id="@+id/profile_list_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:layout_marginStart="15dp"
android:text="@string/no_profiles"/>
</FrameLayout>
@@ -24,7 +24,7 @@
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:textIsSelectable="true"
android:textAppearance="?android:attr/textAppearanceLarge" />
@@ -32,7 +32,7 @@
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:textIsSelectable="true"
android:textColor="?android:textColorSecondary"
android:textAppearance="?android:attr/textAppearanceMedium" />
@@ -41,7 +41,7 @@
android:id="@+id/list_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:textIsSelectable="true"
android:textAppearance="?android:attr/textAppearanceMedium" />
@@ -27,8 +27,8 @@
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false" />
@@ -37,8 +37,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/text1"
android:layout_alignLeft="@android:id/text1"
android:layout_alignRight="@android:id/text1"
android:layout_alignStart="@android:id/text1"
android:layout_alignEnd="@android:id/text1"
android:textColor="?android:textColorSecondary"
android:textAppearance="?android:attr/textAppearanceSmall"
android:singleLine="true"
@@ -19,8 +19,8 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:minHeight="?android:listPreferredItemHeight"
android:background="@drawable/activated_background"
android:gravity="center_vertical" >
@@ -29,7 +29,6 @@
android:duplicateParentState="true"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:layout_marginRight="8dip"
android:layout_marginEnd="8dip"
android:scaleType="centerInside" />
@@ -47,7 +46,6 @@
android:duplicateParentState="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp" />
</org.strongswan.android.ui.widget.CheckableLinearLayout>
@@ -30,7 +30,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/subject_primary"
android:layout_alignLeft="@id/subject_primary"
android:layout_alignStart="@id/subject_primary"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
@@ -34,7 +34,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/text1"
android:layout_alignLeft="@android:id/text1"
android:layout_alignStart="@android:id/text1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
@@ -34,8 +34,8 @@
android:id="@+id/vpn_error_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="12dp"
android:text="Failed to establish VPN: Server is unreachable"
@@ -53,7 +53,7 @@
android:id="@+id/show_log"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:text="@string/show_log"
android:textColor="@color/primary"
android:textSize="14sp"
@@ -84,8 +84,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginTop="10dp"
android:columnCount="2"
android:rowCount="2" >
@@ -93,7 +93,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:gravity="top"
android:text="@string/state_label"
android:textColor="?android:textColorPrimary"
@@ -112,7 +112,7 @@
android:id="@+id/vpn_profile_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:gravity="top"
android:text="@string/profile_label"
android:textColor="?android:textColorPrimary"
@@ -135,8 +135,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:indeterminate="true"
android:visibility="gone"
style="@style/Widget.AppCompat.ProgressBar.Horizontal" />
@@ -146,8 +146,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:text="@string/disconnect"
style="?android:attr/borderlessButtonStyle" >
</Button>
@@ -136,6 +136,7 @@
<string name="profile_import_failed_tls">TLS-Handshake fehlgeschlagen</string>
<string name="profile_import_failed_value">Ungültiger Wert in \"%1$s\"</string>
<string name="profile_import_exists">Dieses VPN Profil existiert bereits, die bestehenden Einstellungen werden ersetzt.</string>
<string name="profile_import_shared_secret">Diese Datei enthält ein Klartext-Passwort. Denken Sie daran, sie nach dem Importieren zu löschen.</string>
<string name="profile_cert_import">Zertifikat aus VPN Profil importieren</string>
<string name="profile_cert_alias">Zertifikat für \"%1$s\"</string>
<string name="profile_profile_id">Profil-ID</string>
@@ -85,6 +85,8 @@
<string name="managed_config_local_bundle_description">Specifies information about the client</string>
<string name="managed_config_local_eap_id_title">Identity/username for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_id_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password</string>
<string name="managed_config_local_eap_password_title">Password for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_password_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally</string>
<string name="managed_config_local_id_title">@string/profile_local_id_label</string>
<string name="managed_config_local_id_description">@string/profile_local_id_hint_user</string>
<string name="managed_config_local_p12_title">@string/profile_user_certificate_label</string>
@@ -138,6 +138,7 @@
<string name="profile_import_failed_tls">TLS handshake failed</string>
<string name="profile_import_failed_value">Invalid value in \"%1$s\"</string>
<string name="profile_import_exists">This VPN profile already exists, its current settings will be replaced.</string>
<string name="profile_import_shared_secret">This file contains a cleartext password. Remember to delete it after importing.</string>
<string name="profile_cert_import">Import certificate from VPN profile</string>
<string name="profile_cert_alias">Certificate for \"%1$s\"</string>
<string name="profile_profile_id">Profile ID</string>
@@ -85,6 +85,8 @@
<string name="managed_config_local_bundle_description">Specifies information about the client</string>
<string name="managed_config_local_eap_id_title">Identity/username for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_id_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password</string>
<string name="managed_config_local_eap_password_title">Password for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_password_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally</string>
<string name="managed_config_local_id_title">@string/profile_local_id_label</string>
<string name="managed_config_local_id_description">@string/profile_local_id_hint_user</string>
<string name="managed_config_local_p12_title">@string/profile_user_certificate_label</string>
@@ -132,6 +132,7 @@
<string name="profile_import_failed_tls">TLS handshake failed</string>
<string name="profile_import_failed_value">Invalid value in \"%1$s\"</string>
<string name="profile_import_exists">This VPN profile already exists, its current settings will be replaced.</string>
<string name="profile_import_shared_secret">This file contains a cleartext password. Remember to delete it after importing.</string>
<string name="profile_cert_import">Import certificate from VPN profile</string>
<string name="profile_cert_alias">Certificate for \"%1$s\"</string>
<string name="profile_profile_id">Profile ID</string>
@@ -85,6 +85,8 @@
<string name="managed_config_local_bundle_description">Specifies information about the client</string>
<string name="managed_config_local_eap_id_title">Identity/username for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_id_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password</string>
<string name="managed_config_local_eap_password_title">Password for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_password_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally</string>
<string name="managed_config_local_id_title">@string/profile_local_id_label</string>
<string name="managed_config_local_id_description">@string/profile_local_id_hint_user</string>
<string name="managed_config_local_p12_title">@string/profile_user_certificate_label</string>
@@ -133,6 +133,7 @@
<string name="profile_import_failed_tls">TLS handshake failed</string>
<string name="profile_import_failed_value">Invalid value in \"%1$s\"</string>
<string name="profile_import_exists">This VPN profile already exists, its current settings will be replaced.</string>
<string name="profile_import_shared_secret">This file contains a cleartext password. Remember to delete it after importing.</string>
<string name="profile_cert_import">Import certificate from VPN profile</string>
<string name="profile_cert_alias">Certificate for \"%1$s\"</string>
<string name="profile_profile_id">Profile ID</string>
@@ -85,6 +85,8 @@
<string name="managed_config_local_bundle_description">Specifies information about the client</string>
<string name="managed_config_local_eap_id_title">Identity/username for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_id_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password</string>
<string name="managed_config_local_eap_password_title">Password for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_password_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally</string>
<string name="managed_config_local_id_title">@string/profile_local_id_label</string>
<string name="managed_config_local_id_description">@string/profile_local_id_hint_user</string>
<string name="managed_config_local_p12_title">@string/profile_user_certificate_label</string>
@@ -132,6 +132,7 @@
<string name="profile_import_failed_tls">TLS握手失败</string>
<string name="profile_import_failed_value">无效的值: \"%1$s\"</string>
<string name="profile_import_exists">此VPN配置已经存在,当前设定将被覆盖。</string>
<string name="profile_import_shared_secret">This file contains a cleartext password. Remember to delete it after importing.</string>
<string name="profile_cert_import">从VPN配置导入证书</string>
<string name="profile_cert_alias">\"%1$s\" 所对应的证书</string>
<string name="profile_profile_id">配置文件ID</string>
@@ -85,6 +85,8 @@
<string name="managed_config_local_bundle_description">Specifies information about the client</string>
<string name="managed_config_local_eap_id_title">Identity/username for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_id_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password</string>
<string name="managed_config_local_eap_password_title">Password for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_password_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally</string>
<string name="managed_config_local_id_title">@string/profile_local_id_label</string>
<string name="managed_config_local_id_description">@string/profile_local_id_hint_user</string>
<string name="managed_config_local_p12_title">@string/profile_user_certificate_label</string>
@@ -132,6 +132,7 @@
<string name="profile_import_failed_tls">TLS連線失敗</string>
<string name="profile_import_failed_value">Invalid value in \"%1$s\"</string>
<string name="profile_import_exists">這個VPN設定檔已經存在,當前設定檔會被覆蓋。</string>
<string name="profile_import_shared_secret">This file contains a cleartext password. Remember to delete it after importing.</string>
<string name="profile_cert_import">從VPN設定檔匯入憑證</string>
<string name="profile_cert_alias">\"%1$s\" 對應的憑證</string>
<string name="profile_profile_id">Profile ID</string>
@@ -85,6 +85,8 @@
<string name="managed_config_local_bundle_description">Specifies information about the client</string>
<string name="managed_config_local_eap_id_title">Identity/username for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_id_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password</string>
<string name="managed_config_local_eap_password_title">Password for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_password_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally</string>
<string name="managed_config_local_id_title">@string/profile_local_id_label</string>
<string name="managed_config_local_id_description">@string/profile_local_id_hint_user</string>
<string name="managed_config_local_p12_title">@string/profile_user_certificate_label</string>
@@ -136,6 +136,7 @@
<string name="profile_import_failed_tls">TLS handshake failed</string>
<string name="profile_import_failed_value">Invalid value in \"%1$s\"</string>
<string name="profile_import_exists">This VPN profile already exists, its current settings will be replaced.</string>
<string name="profile_import_shared_secret">This file contains a cleartext password. Remember to delete it after importing.</string>
<string name="profile_cert_import">Import certificate from VPN profile</string>
<string name="profile_cert_alias">Certificate for \"%1$s\"</string>
<string name="profile_profile_id">Profile ID</string>
@@ -85,6 +85,8 @@
<string name="managed_config_local_bundle_description">Specifies information about the client</string>
<string name="managed_config_local_eap_id_title">Identity/username for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_id_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password</string>
<string name="managed_config_local_eap_password_title">Password for EAP authentication (Optional)</string>
<string name="managed_config_local_eap_password_description">If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally</string>
<string name="managed_config_local_id_title">@string/profile_local_id_label</string>
<string name="managed_config_local_id_description">@string/profile_local_id_hint_user</string>
<string name="managed_config_local_p12_title">@string/profile_user_certificate_label</string>
@@ -176,6 +176,13 @@
android:restrictionType="string"
android:title="@string/managed_config_local_eap_id_title" />
<restriction
android:defaultValue=""
android:description="@string/managed_config_local_eap_password_description"
android:key="password"
android:restrictionType="string"
android:title="@string/managed_config_local_eap_password_title" />
<restriction
android:defaultValue=""
android:description="@string/managed_config_local_id_description"