diff --git a/main/src/main/AndroidManifest.xml b/main/src/main/AndroidManifest.xml
index 383533fd71..4aa454c132 100644
--- a/main/src/main/AndroidManifest.xml
+++ b/main/src/main/AndroidManifest.xml
@@ -139,6 +139,10 @@
android:name=".api.ResumeVPN"
android:exported="true"
android:targetActivity=".api.RemoteAction" />
+
diff --git a/main/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl b/main/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl
index 39b531060d..5e259d29f6 100644
--- a/main/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl
+++ b/main/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl
@@ -73,4 +73,10 @@ interface IOpenVPNAPIService {
* up to now the only extra that can be put is a boolean "de.blinkt.openvpn.api.ALLOW_VPN_BYPASS"
*/
APIVpnProfile addNewVPNProfileWithExtras (String name, boolean userEditable, String config, in Bundle extras);
+
+ /** Get the current default profile, or null if there is no default */
+ @nullable APIVpnProfile getDefaultProfile();
+
+ /** Set the default profile by UUID */
+ void setDefaultProfile (String profileUUID);
}
\ No newline at end of file
diff --git a/main/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java b/main/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
index 9d47c01d2b..cf310dbc74 100644
--- a/main/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
+++ b/main/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
@@ -47,8 +47,8 @@ public void writeToParcel(Parcel dest, int flags) {
//dest.writeString(mProfileCreator);
}
- public static final Parcelable.Creator CREATOR
- = new Parcelable.Creator() {
+ public static final Creator CREATOR
+ = new Creator() {
public APIVpnProfile createFromParcel(Parcel in) {
return new APIVpnProfile(in);
}
diff --git a/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java
index bdf3e29c1c..f2973e5a24 100644
--- a/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java
+++ b/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java
@@ -13,6 +13,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.SharedPreferences;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build;
@@ -37,6 +38,7 @@
import de.blinkt.openvpn.core.ConnectionStatus;
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
import de.blinkt.openvpn.core.OpenVPNService;
+import de.blinkt.openvpn.core.Preferences;
import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VPNLaunchHelper;
import de.blinkt.openvpn.core.VpnStatus;
@@ -109,6 +111,10 @@ public void onCreate() {
}
+ private APIVpnProfile apiVpnProfileFromVpnProfile(VpnProfile vp) {
+ return new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator);
+ }
+
private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() {
@Override
@@ -121,7 +127,7 @@ public List getProfiles() throws RemoteException {
for (VpnProfile vp : pm.getProfiles()) {
if (!vp.profileDeleted)
- profiles.add(new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator));
+ profiles.add(apiVpnProfileFromVpnProfile(vp));
}
return profiles;
@@ -232,7 +238,7 @@ public APIVpnProfile addNewVPNProfileWithExtras(String name, boolean userEditabl
vp.addChangeLogEntry("AIDL API created profile");
pm.saveProfile(ExternalOpenVPNService.this, vp);
pm.saveProfileList(ExternalOpenVPNService.this);
- return new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator);
+ return apiVpnProfileFromVpnProfile(vp);
} catch (IOException e) {
VpnStatus.logException(e);
return null;
@@ -330,6 +336,37 @@ public void resume() throws RemoteException {
mService.userPause(false);
}
+
+ @Override
+ public APIVpnProfile getDefaultProfile() throws RemoteException {
+ mExtAppDb.checkOpenVPNPermission(getPackageManager());
+ ProfileManager pm = ProfileManager.getInstance(getBaseContext());
+ SharedPreferences prefs = Preferences.getDefaultSharedPreferences(getBaseContext());
+ String profileUUID = prefs.getString("alwaysOnVpn", null);
+ if (profileUUID == null) {
+ return null;
+ }
+ VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID);
+ if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found) {
+ VpnStatus.logInfo("Default profile is currently set to unknown UUID " + profileUUID);
+ return null;
+ }
+ APIVpnProfile result = apiVpnProfileFromVpnProfile(vp);
+ return result;
+ }
+
+ @Override
+ public void setDefaultProfile(String profileUUID) throws RemoteException {
+ mExtAppDb.checkOpenVPNPermission(getPackageManager());
+ ProfileManager pm = ProfileManager.getInstance(getBaseContext());
+ VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID);
+ if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found)
+ throw new RemoteException(getString(vp.checkProfile(getApplicationContext())));
+ SharedPreferences prefs = Preferences.getDefaultSharedPreferences(getBaseContext());
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("alwaysOnVpn", vp.getUUIDString());
+ editor.apply();
+ }
};
@@ -425,4 +462,4 @@ private void sendUpdate(IOpenVPNStatusCallback broadcastItem,
-}
\ No newline at end of file
+}
diff --git a/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java b/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java
index 55322e7f4c..f2ff173576 100644
--- a/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java
+++ b/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java
@@ -10,6 +10,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -19,7 +20,9 @@
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
import de.blinkt.openvpn.core.OpenVPNService;
+import de.blinkt.openvpn.core.Preferences;
import de.blinkt.openvpn.core.ProfileManager;
+import de.blinkt.openvpn.core.VpnStatus;
public class RemoteAction extends Activity {
@@ -61,6 +64,33 @@ protected void onResume() {
}
+ private void connectVPN(Intent intent) {
+ String vpnName = intent.getStringExtra(EXTRA_NAME);
+ VpnProfile profile = ProfileManager.getInstance(this).getProfileByName(vpnName);
+ if (profile == null) {
+ Toast.makeText(this, String.format("Vpn profile %s from API call not found", vpnName), Toast.LENGTH_LONG).show();
+ } else {
+ Intent startVPN = new Intent(this, LaunchVPN.class);
+ startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
+ startVPN.putExtra(OpenVPNService.EXTRA_START_REASON, ".api.ConnectVPN call");
+ startVPN.setAction(Intent.ACTION_MAIN);
+ startActivity(startVPN);
+ }
+ }
+
+ private void setDefaultVPN(Intent intent) {
+ String defaultVpnName = intent.getStringExtra(EXTRA_NAME);
+ VpnProfile defaultProfile = ProfileManager.getInstance(this).getProfileByName(defaultVpnName);
+ if (defaultProfile == null) {
+ Toast.makeText(this, String.format("Vpn profile %s from API call not found", defaultVpnName), Toast.LENGTH_LONG).show();
+ } else {
+ SharedPreferences prefs = Preferences.getDefaultSharedPreferences(this);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("alwaysOnVpn", defaultProfile.getUUIDString());
+ editor.apply();
+ }
+ }
+
private void performAction() throws RemoteException {
if (!mService.isAllowedExternalApp(getCallingPackage())) {
@@ -86,17 +116,10 @@ private void performAction() throws RemoteException {
mService.userPause(false);
break;
case ".api.ConnectVPN":
- String vpnName = intent.getStringExtra(EXTRA_NAME);
- VpnProfile profile = ProfileManager.getInstance(this).getProfileByName(vpnName);
- if (profile == null) {
- Toast.makeText(this, String.format("Vpn profile %s from API call not found", vpnName), Toast.LENGTH_LONG).show();
- } else {
- Intent startVPN = new Intent(this, LaunchVPN.class);
- startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
- startVPN.putExtra(OpenVPNService.EXTRA_START_REASON, ".api.ConnectVPN call");
- startVPN.setAction(Intent.ACTION_MAIN);
- startActivity(startVPN);
- }
+ connectVPN(intent);
+ break;
+ case ".api.SetDefaultVPN":
+ setDefaultVPN(intent);
break;
}
finish();
diff --git a/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl b/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl
index 1989b771d4..5e259d29f6 100644
--- a/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl
+++ b/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl
@@ -18,14 +18,14 @@ interface IOpenVPNAPIService {
boolean addVPNProfile (String name, String config);
/** start a profile using a config as inline string. Make sure that all needed data is inlined,
- * e.g., using ... or ...
+ * e.g., using ... or ...
* See the OpenVPN manual page for more on inlining files */
- void startVPN (String inlineconfig);
+ void startVPN (in String inlineconfig);
/** This permission framework is used to avoid confused deputy style attack to the VPN
* calling this will give null if the app is allowed to use the external API and an Intent
* that can be launched to request permissions otherwise */
- Intent prepare (String packagename);
+ Intent prepare (in String packagename);
/** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance,
* if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent
@@ -44,15 +44,15 @@ interface IOpenVPNAPIService {
/**
* Registers to receive OpenVPN Status Updates
*/
- void registerStatusCallback(IOpenVPNStatusCallback cb);
+ void registerStatusCallback(in IOpenVPNStatusCallback cb);
/**
* Remove a previously registered callback interface.
*/
- void unregisterStatusCallback(IOpenVPNStatusCallback cb);
+ void unregisterStatusCallback(in IOpenVPNStatusCallback cb);
/** Remove a profile by UUID */
- void removeProfile (String profileUUID);
+ void removeProfile (in String profileUUID);
/** Request a socket to be protected as a VPN socket would be. Useful for creating
* a helper socket for an app controlling OpenVPN
@@ -64,9 +64,19 @@ interface IOpenVPNAPIService {
/** Use a profile with all certificates etc. embedded */
APIVpnProfile addNewVPNProfile (String name, boolean userEditable, String config);
+ /** Same as startVPN(String), but also takes a Bundle with extra parameters,
+ * which will be applied to the created VPNProfile (e.g. allow vpn bypass). */
+ void startVPNwithExtras(in String inlineconfig, in Bundle extras);
+
/** Same as addNewVPNProfile(String, boolean, String) but giving possibility to pass a Bundle like
* in startVPNwithExtras(String, Bundle) to apply e.g. "allow vpn bypass" to profile.
* up to now the only extra that can be put is a boolean "de.blinkt.openvpn.api.ALLOW_VPN_BYPASS"
*/
APIVpnProfile addNewVPNProfileWithExtras (String name, boolean userEditable, String config, in Bundle extras);
+
+ /** Get the current default profile, or null if there is no default */
+ @nullable APIVpnProfile getDefaultProfile();
+
+ /** Set the default profile by UUID */
+ void setDefaultProfile (String profileUUID);
}
\ No newline at end of file
diff --git a/remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java b/remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
index 65c6ad5762..cf310dbc74 100644
--- a/remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
+++ b/remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
@@ -1,6 +1,8 @@
/*
- * Copyright (c) 2012-2015 Arne Schwabe
- * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ * Copyright (c) 2012-2016 Arne Schwabe
+ * This file is used for implementing the external API and this file like the AIDL and is exempted
+ * from the GPLv2.
+ *
*/
package de.blinkt.openvpn.api;
diff --git a/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java b/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java
index d98fdedd8d..c4e92f27c1 100644
--- a/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java
+++ b/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java
@@ -52,6 +52,7 @@ public class MainFragment extends Fragment implements View.OnClickListener, Hand
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
v.findViewById(R.id.disconnect).setOnClickListener(this);
+ v.findViewById(R.id.setDefaultProfile).setOnClickListener(this);
v.findViewById(R.id.getMyIP).setOnClickListener(this);
v.findViewById(R.id.startembedded).setOnClickListener(this);
v.findViewById(R.id.addNewProfile).setOnClickListener(this);
@@ -70,6 +71,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
private static final int MSG_UPDATE_MYIP = 1;
private static final int START_PROFILE_EMBEDDED = 2;
private static final int START_PROFILE_BYUUID = 3;
+ private static final int SET_DEFAULT_PROFILE_BYUUID = 4;
private static final int ICS_OPENVPN_PERMISSION = 7;
private static final int PROFILE_ADD_NEW = 8;
private static final int PROFILE_ADD_NEW_EDIT = 9;
@@ -195,9 +197,12 @@ protected void listVPNs() {
try {
List list = mService.getProfiles();
+ APIVpnProfile defaultProfile = mService.getDefaultProfile();
+ String defaultUUID = defaultProfile != null ? defaultProfile.mUUID : null;
String all="List:";
for(APIVpnProfile vp:list.subList(0, Math.min(5, list.size()))) {
- all = all + vp.mName + ":" + vp.mUUID + "\n";
+ String suffix = (vp.mUUID.equals(defaultUUID)) ? " (default)" : "";
+ all = all + vp.mName + ":" + vp.mUUID + suffix + "\n";
}
if (list.size() > 5)
@@ -253,6 +258,14 @@ public void onClick(View v) {
e.printStackTrace();
}
break;
+ case R.id.setDefaultProfile:
+ try {
+ prepareStartProfile(SET_DEFAULT_PROFILE_BYUUID);
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ break;
case R.id.getMyIP:
// Socket handling is not allowed on main thread
@@ -317,6 +330,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
} catch (RemoteException e) {
e.printStackTrace();
}
+ if(requestCode==SET_DEFAULT_PROFILE_BYUUID)
+ try {
+ mService.setDefaultProfile(mStartUUID);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
if (requestCode == ICS_OPENVPN_PERMISSION) {
listVPNs();
try {
diff --git a/remoteExample/src/main/res/layout/fragment_main.xml b/remoteExample/src/main/res/layout/fragment_main.xml
index 6b8102e274..0780bba450 100644
--- a/remoteExample/src/main/res/layout/fragment_main.xml
+++ b/remoteExample/src/main/res/layout/fragment_main.xml
@@ -63,6 +63,14 @@
android:layout_toRightOf="@+id/startVPN"
android:text="@string/disconnect" />
+
+