summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcyberta <cyberta@riseup.net>2019-09-19 07:34:54 -0700
committercyberta <cyberta@riseup.net>2019-09-19 07:34:54 -0700
commit7820e8c0819a10c5b4729678607681fcfe30cbae (patch)
tree43590440908ce85ef286487bb5c44155b3de1f8e
parent303dd2a0e498fac87144b2d7ac930b27fe1bc7e8 (diff)
parent2e1c94d3f51dc6d667435b2a2bbd81a036d57bae (diff)
Merge branch 'master' into 'master'
[New Feature] Option for excluding apps from VPN See merge request leap/bitmask_android!93
-rw-r--r--app/src/androidTest/legacy/TestGatewaysManager.java6
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Constants.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java8
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java19
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/fragments/ExcludeAppsFragment.java329
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java19
-rwxr-xr-xapp/src/main/res/drawable-hdpi/ic_search_white_24dp.pngbin0 -> 396 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.pngbin0 -> 1628 bytes
-rwxr-xr-xapp/src/main/res/drawable-mdpi/ic_search_white_24dp.pngbin0 -> 247 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.pngbin0 -> 1192 bytes
-rwxr-xr-xapp/src/main/res/drawable-xhdpi/ic_search_white_24dp.pngbin0 -> 465 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.pngbin0 -> 1930 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/bg_switchbar.xml9
-rwxr-xr-xapp/src/main/res/drawable-xxhdpi/ic_search_white_24dp.pngbin0 -> 728 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.pngbin0 -> 2902 bytes
-rwxr-xr-xapp/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.pngbin0 -> 915 bytes
-rw-r--r--app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.pngbin0 -> 3686 bytes
-rw-r--r--app/src/main/res/layout/allowed_application_layout.xml61
-rw-r--r--app/src/main/res/layout/allowed_vpn_apps.xml60
-rw-r--r--app/src/main/res/layout/s_layout.xml12
-rw-r--r--app/src/main/res/menu/allowed_apps.xml15
-rw-r--r--app/src/main/res/values/colors.xml2
-rwxr-xr-xapp/src/main/res/values/strings-icsopenvpn.xml1
-rw-r--r--app/src/main/res/values/strings.xml3
-rw-r--r--app/src/main/res/values/untranslatable.xml12
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java34
28 files changed, 581 insertions, 13 deletions
diff --git a/app/src/androidTest/legacy/TestGatewaysManager.java b/app/src/androidTest/legacy/TestGatewaysManager.java
index 02c521be..80438073 100644
--- a/app/src/androidTest/legacy/TestGatewaysManager.java
+++ b/app/src/androidTest/legacy/TestGatewaysManager.java
@@ -119,7 +119,7 @@ public class TestGatewaysManager extends InstrumentationTestCase {
eip_definition = new JSONObject(assets.toString(TestConstants.EIP_DEFINITION_FILE));
JSONObject secrets = new JSONObject(assets.toString(TestConstants.SECRETS_FILE));
JSONObject gateway = new JSONObject(assets.toString(TestConstants.GATEWAY_FILE));
- this.gateway = new Gateway(eip_definition, secrets, gateway);
+ this.gateway = new Gateway(eip_definition, secrets, gateway, context);
} catch (Exception e) {
e.printStackTrace();
}
@@ -137,7 +137,7 @@ public class TestGatewaysManager extends InstrumentationTestCase {
capabilitiesJson.put("protocols", protocolJsonArray);
gatewayJson.put("protocols", protocolJsonArray);
}
- this.gateway = new Gateway(eip_definition, secrets, gateways.getJSONObject(0));
+ this.gateway = new Gateway(eip_definition, secrets, gateways.getJSONObject(0), context);
} catch (JSONException e) {
e.printStackTrace();
assertFalse(true);
@@ -153,7 +153,7 @@ public class TestGatewaysManager extends InstrumentationTestCase {
eip_definition = new JSONObject(assets.toString(TestConstants.EIP_DEFINITION_FILE));
JSONObject secrets = new JSONObject(assets.toString(TestConstants.SECRETS_FILE).replace("6u6", "7u7"));
JSONObject gateway = new JSONObject(assets.toString(TestConstants.GATEWAY_FILE));
- this.gateway = new Gateway(eip_definition, secrets, gateway);
+ this.gateway = new Gateway(eip_definition, secrets, gateway, context);
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java
index 42df6d1d..18338a73 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java
@@ -13,6 +13,7 @@ public interface Constants {
String ALWAYS_ON_SHOW_DIALOG = "DIALOG.ALWAYS_ON_SHOW_DIALOG";
String CLEARLOG = "clearlogconnect";
String LAST_USED_PROFILE = "last_used_profile";
+ String EXCLUDED_APPS = "excluded_apps";
//////////////////////////////////////////////
diff --git a/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java b/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java
index 89aeb4be..024bfaba 100644
--- a/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java
+++ b/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java
@@ -45,6 +45,7 @@ public class DrawerSettingsAdapter extends BaseAdapter {
public static final int BATTERY_SAVER = 3;
public static final int ALWAYS_ON = 4;
public static final int DONATE = 5;
+ public static final int SELECT_APPS = 6;
//view types
public final static int VIEW_SIMPLE_TEXT = 0;
diff --git a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java
index 640c143a..a604c536 100644
--- a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java
@@ -59,6 +59,7 @@ import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.fragments.AboutFragment;
import se.leap.bitmaskclient.fragments.AlwaysOnDialog;
import se.leap.bitmaskclient.fragments.LogFragment;
+import se.leap.bitmaskclient.fragments.ExcludeAppsFragment;
import static android.content.Context.MODE_PRIVATE;
import static se.leap.bitmaskclient.BitmaskApp.getRefWatcher;
@@ -74,8 +75,10 @@ import static se.leap.bitmaskclient.DrawerSettingsAdapter.DONATE;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.DrawerSettingsItem.getSimpleTextInstance;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.DrawerSettingsItem.getSwitchInstance;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.LOG;
+import static se.leap.bitmaskclient.DrawerSettingsAdapter.SELECT_APPS;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.SWITCH_PROVIDER;
import static se.leap.bitmaskclient.R.string.about_fragment_title;
+import static se.leap.bitmaskclient.R.string.exclude_apps_fragment_title;
import static se.leap.bitmaskclient.R.string.donate_title;
import static se.leap.bitmaskclient.R.string.log_fragment_title;
import static se.leap.bitmaskclient.R.string.switch_provider_menu_option;
@@ -268,6 +271,7 @@ public class NavigationDrawerFragment extends Fragment {
if (isDefaultBitmask()) {
settingsListAdapter.addItem(getSimpleTextInstance(getContext(), getString(switch_provider_menu_option), R.drawable.ic_switch_provider_36, SWITCH_PROVIDER));
}
+ settingsListAdapter.addItem(getSimpleTextInstance(getContext(), getString(exclude_apps_fragment_title), R.drawable.ic_shield_remove_grey600_36dp, SELECT_APPS));
settingsListAdapter.addItem(getSimpleTextInstance(getContext(), getString(log_fragment_title), R.drawable.ic_log_36, LOG));
if (ENABLE_DONATION) {
settingsListAdapter.addItem(getSimpleTextInstance(getContext(), getString(donate_title), R.drawable.ic_donate_36, DONATE));
@@ -494,6 +498,10 @@ public class NavigationDrawerFragment extends Fragment {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(DONATION_URL));
startActivity(browserIntent);
break;
+ case SELECT_APPS:
+ fragment = new ExcludeAppsFragment();
+ setActionBarTitle(exclude_apps_fragment_title);
+ break;
default:
break;
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
index 55ade1ae..09b33845 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -16,6 +16,9 @@
*/
package se.leap.bitmaskclient.eip;
+import android.content.Context;
+import android.content.SharedPreferences;
+
import com.google.gson.Gson;
import org.json.JSONException;
@@ -23,9 +26,13 @@ import org.json.JSONObject;
import java.io.IOException;
import java.io.StringReader;
+import java.util.HashSet;
+import java.util.Set;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.ConfigParser;
+import se.leap.bitmaskclient.BitmaskApp;
+import se.leap.bitmaskclient.utils.PreferenceHelper;
/**
* Gateway provides objects defining gateways and their metadata.
@@ -52,7 +59,7 @@ public class Gateway {
* Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json
* and create a VpnProfile belonging to it.
*/
- public Gateway(JSONObject eip_definition, JSONObject secrets, JSONObject gateway) {
+ public Gateway(JSONObject eip_definition, JSONObject secrets, JSONObject gateway, Context context) {
this.gateway = gateway;
this.secrets = secrets;
@@ -62,7 +69,17 @@ public class Gateway {
mName = locationAsName(eip_definition);
mVpnProfile = createVPNProfile();
+ System.out.println("###########" + mName + "###########");
mVpnProfile.mName = mName;
+
+ Set<String> excludedAppsVpn = PreferenceHelper.getExcludedApps(context);
+ if (excludedAppsVpn != null) {
+ mVpnProfile.mAllowedAppsVpn = new HashSet<>(excludedAppsVpn);
+ }
+ else {
+ mVpnProfile.mAllowedAppsVpn = null;
+ }
+
}
private JSONObject getGeneralConfiguration(JSONObject eip_definition) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
index 060843fd..6bd7b4a3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -93,7 +93,7 @@ public class GatewaysManager {
JSONObject gw = gatewaysDefined.getJSONObject(i);
if (isOpenVpnGateway(gw)) {
JSONObject secrets = secretsConfiguration();
- Gateway aux = new Gateway(eipDefinition, secrets, gw);
+ Gateway aux = new Gateway(eipDefinition, secrets, gw, this.context);
if (!gateways.contains(aux)) {
addGateway(aux);
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/ExcludeAppsFragment.java b/app/src/main/java/se/leap/bitmaskclient/fragments/ExcludeAppsFragment.java
new file mode 100644
index 00000000..066c9636
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/fragments/ExcludeAppsFragment.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2012-2016 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
+package se.leap.bitmaskclient.fragments;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.support.v4.app.Fragment;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.CompoundButton;
+import android.widget.Filter;
+import android.widget.Filterable;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.SearchView;
+import android.widget.TextView;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.Vector;
+
+import de.blinkt.openvpn.VpnProfile;
+
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.utils.PreferenceHelper;
+
+/**
+ * Created by arne on 16.11.14.
+ */
+public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemClickListener, CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+ private ListView mListView;
+ private VpnProfile mProfile;
+ private PackageAdapter mListAdapter;
+
+ private SharedPreferences allow_apps;
+ private SharedPreferences.Editor allow_apps_editor;
+ private Set<String> apps;
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ AppViewHolder avh = (AppViewHolder) view.getTag();
+ avh.checkBox.toggle();
+ }
+
+ @Override
+ public void onClick(View v) {
+
+ }
+
+ static class AppViewHolder {
+ public ApplicationInfo mInfo;
+ public View rootView;
+ public TextView appName;
+ public ImageView appIcon;
+ //public TextView appSize;
+ //public TextView disabled;
+ public CompoundButton checkBox;
+
+ static public AppViewHolder createOrRecycle(LayoutInflater inflater, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = inflater.inflate(R.layout.allowed_application_layout, parent, false);
+
+ // Creates a ViewHolder and store references to the two children views
+ // we want to bind data to.
+ AppViewHolder holder = new AppViewHolder();
+ holder.rootView = convertView;
+ holder.appName = (TextView) convertView.findViewById(R.id.app_name);
+ holder.appIcon = (ImageView) convertView.findViewById(R.id.app_icon);
+ holder.checkBox = (CompoundButton) convertView.findViewById(R.id.app_selected);
+ convertView.setTag(holder);
+
+ return holder;
+ } else {
+ // Get the ViewHolder back to get fast access to the TextView
+ // and the ImageView.
+ return (AppViewHolder) convertView.getTag();
+ }
+ }
+
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ String packageName = (String) buttonView.getTag();
+
+ if (isChecked) {
+ Log.d("openvpn", "adding to allowed apps" + packageName);
+
+ apps.add(packageName);
+
+ } else {
+ Log.d("openvpn", "removing from allowed apps" + packageName);
+
+ apps.remove(packageName);
+ }
+
+ PreferenceHelper.setExcludedApps(this.getContext(), apps);
+ }
+
+
+ class PackageAdapter extends BaseAdapter implements Filterable {
+ private Vector<ApplicationInfo> mPackages;
+ private final LayoutInflater mInflater;
+ private final PackageManager mPm;
+ private ItemFilter mFilter = new ItemFilter();
+ private Vector<ApplicationInfo> mFilteredData;
+
+
+ private class ItemFilter extends Filter {
+ @Override
+ protected FilterResults performFiltering(CharSequence constraint) {
+
+ String filterString = constraint.toString().toLowerCase(Locale.getDefault());
+
+ FilterResults results = new FilterResults();
+
+
+ int count = mPackages.size();
+ final Vector<ApplicationInfo> nlist = new Vector<>(count);
+
+ for (int i = 0; i < count; i++) {
+ ApplicationInfo pInfo = mPackages.get(i);
+ CharSequence appName = pInfo.loadLabel(mPm);
+
+ if (TextUtils.isEmpty(appName))
+ appName = pInfo.packageName;
+
+ if (appName instanceof String) {
+ if (((String) appName).toLowerCase(Locale.getDefault()).contains(filterString))
+ nlist.add(pInfo);
+ } else {
+ if (appName.toString().toLowerCase(Locale.getDefault()).contains(filterString))
+ nlist.add(pInfo);
+ }
+ }
+ results.values = nlist;
+ results.count = nlist.size();
+
+ return results;
+ }
+
+ @Override
+ protected void publishResults(CharSequence constraint, FilterResults results) {
+ mFilteredData = (Vector<ApplicationInfo>) results.values;
+ notifyDataSetChanged();
+ }
+
+ }
+
+
+ PackageAdapter(Context c, VpnProfile vp) {
+ mPm = c.getPackageManager();
+ mProfile = vp;
+ mInflater = LayoutInflater.from(c);
+
+ mPackages = new Vector<>();
+ mFilteredData = mPackages;
+ }
+
+ private void populateList(Activity c) {
+ List<ApplicationInfo> installedPackages = mPm.getInstalledApplications(PackageManager.GET_META_DATA);
+
+ // Remove apps not using Internet
+
+ int androidSystemUid = 0;
+ ApplicationInfo system = null;
+ Vector<ApplicationInfo> apps = new Vector<ApplicationInfo>();
+
+ try {
+ system = mPm.getApplicationInfo("android", PackageManager.GET_META_DATA);
+ androidSystemUid = system.uid;
+ apps.add(system);
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+
+
+ for (ApplicationInfo app : installedPackages) {
+
+ if (mPm.checkPermission(Manifest.permission.INTERNET, app.packageName) == PackageManager.PERMISSION_GRANTED &&
+ app.uid != androidSystemUid) {
+
+ apps.add(app);
+ }
+ }
+
+ Collections.sort(apps, new ApplicationInfo.DisplayNameComparator(mPm));
+ mPackages = apps;
+ mFilteredData = apps;
+ c.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ notifyDataSetChanged();
+ }
+ });
+ }
+
+ @Override
+ public int getCount() {
+ return mFilteredData.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mFilteredData.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mFilteredData.get(position).packageName.hashCode();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ AppViewHolder viewHolder = AppViewHolder.createOrRecycle(mInflater, convertView, parent);
+
+ viewHolder.mInfo = mFilteredData.get(position);
+ final ApplicationInfo mInfo = mFilteredData.get(position);
+
+
+ CharSequence appName = mInfo.loadLabel(mPm);
+
+ if (TextUtils.isEmpty(appName))
+ appName = mInfo.packageName;
+ viewHolder.appName.setText(appName);
+ viewHolder.appIcon.setImageDrawable(mInfo.loadIcon(mPm));
+ viewHolder.checkBox.setTag(mInfo.packageName);
+ viewHolder.checkBox.setOnCheckedChangeListener(ExcludeAppsFragment.this);
+ viewHolder.checkBox.setChecked(apps.contains(mInfo.packageName));
+
+ return viewHolder.rootView;
+ }
+
+ @Override
+ public Filter getFilter() {
+ return mFilter;
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ apps = PreferenceHelper.getExcludedApps(this.getContext());
+
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.allowed_apps, menu);
+
+ SearchView searchView = (SearchView) menu.findItem( R.id.app_search_widget ).getActionView();
+ searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ mListView.setFilterText(query);
+ mListView.setTextFilterEnabled(true);
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ mListView.setFilterText(newText);
+ if (TextUtils.isEmpty(newText))
+ mListView.setTextFilterEnabled(false);
+ else
+ mListView.setTextFilterEnabled(true);
+
+ return true;
+ }
+ });
+ searchView.setOnCloseListener(new SearchView.OnCloseListener() {
+ @Override
+ public boolean onClose() {
+ mListView.clearTextFilter();
+ mListAdapter.getFilter().filter("");
+ return false;
+ }
+ });
+
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.allowed_vpn_apps, container, false);
+
+ mListView = v.findViewById(android.R.id.list);
+
+ mListAdapter = new PackageAdapter(getActivity(), mProfile);
+ mListView.setAdapter(mListAdapter);
+ mListView.setOnItemClickListener(this);
+
+ mListView.setEmptyView(v.findViewById(R.id.loading_container));
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ mListAdapter.populateList(getActivity());
+ }
+ }).start();
+
+ return v;
+ }
+
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
index f5cf590b..9eb4c972 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
@@ -12,9 +12,11 @@ import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Set;
import de.blinkt.openvpn.VpnProfile;
import se.leap.bitmaskclient.Provider;
@@ -29,6 +31,7 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.Constants.EXCLUDED_APPS;
/**
* Created by cyberta on 18.03.18.
@@ -256,6 +259,21 @@ public class PreferenceHelper {
return result;
}
+ public static void setExcludedApps(Context context, Set<String> apps) {
+ SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences.Editor prefsedit = prefs.edit();
+ prefsedit.putStringSet(EXCLUDED_APPS, apps);
+ prefsedit.apply();
+ }
+
+ public static Set<String> getExcludedApps(Context context) {
+ if (context == null) {
+ return null;
+ }
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ return preferences.getStringSet(EXCLUDED_APPS, new HashSet<>());
+ }
+
public static String getString(Context context, String key, String defValue) {
SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
return preferences.getString(key, defValue);
@@ -266,4 +284,5 @@ public class PreferenceHelper {
preferences.edit().putString(key, value).apply();
}
+
}
diff --git a/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png
new file mode 100755
index 00000000..bbfbc96c
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png
new file mode 100644
index 00000000..98dec84c
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png
new file mode 100755
index 00000000..faefc59c
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png
new file mode 100644
index 00000000..d4b61030
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png
new file mode 100755
index 00000000..bfc3e393
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png
new file mode 100644
index 00000000..3eae1fdc
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/bg_switchbar.xml b/app/src/main/res/drawable-xxhdpi/bg_switchbar.xml
new file mode 100644
index 00000000..7af57ad3
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/bg_switchbar.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (c) 2012-2016 Arne Schwabe
+ ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/switchbar" />
+</shape> \ No newline at end of file
diff --git a/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png
new file mode 100755
index 00000000..abbb9895
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png
new file mode 100644
index 00000000..c6761744
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png
new file mode 100755
index 00000000..dd5adfc7
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png
new file mode 100644
index 00000000..ad08be94
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png
Binary files differ
diff --git a/app/src/main/res/layout/allowed_application_layout.xml b/app/src/main/res/layout/allowed_application_layout.xml
new file mode 100644
index 00000000..d8d846f9
--- /dev/null
+++ b/app/src/main/res/layout/allowed_application_layout.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (c) 2012-2016 Arne Schwabe
+ ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ -->
+
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"
+ android:columnCount="4"
+ tools:ignore="RtlCompat">
+
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_width="@android:dimen/app_icon_size"
+ android:layout_height="@android:dimen/app_icon_size"
+ android:layout_rowSpan="1"
+ android:layout_marginEnd="8dip"
+ android:scaleType="centerInside"
+ tools:background="@drawable/icon"
+ android:contentDescription="@null" />
+
+ <TextView
+ tools:text="@string/app"
+ android:id="@+id/app_name"
+ android:layout_width="0dip"
+ android:layout_columnSpan="2"
+ android:layout_rowSpan="1"
+ android:layout_gravity="fill_horizontal|center_vertical"
+ android:layout_marginTop="2dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAlignment="viewStart" />
+
+ <CheckBox android:id="@+id/app_selected"
+ android:layout_marginStart="8dip"
+ android:layout_gravity="center_vertical"
+ android:layout_rowSpan="1"
+ android:visibility="visible" />
+
+<!-- <TextView
+ android:id="@+id/app_size"
+ android:layout_width="0dip"
+ android:layout_gravity="fill_horizontal|top"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAlignment="viewStart" /> -->
+
+ <!-- <TextView
+ android:id="@+id/app_disabled"
+ android:layout_marginStart="8dip"
+ android:layout_gravity="top"
+ android:textAppearance="?android:attr/textAppearanceSmall" /> -->
+
+</GridLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/allowed_vpn_apps.xml b/app/src/main/res/layout/allowed_vpn_apps.xml
new file mode 100644
index 00000000..1219da54
--- /dev/null
+++ b/app/src/main/res/layout/allowed_vpn_apps.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (c) 2012-2016 Arne Schwabe
+ ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ tools:ignore="RtlCompat"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textStyle="bold"
+ android:textColor="@color/colorWarning"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/warning_exclude_apps_message" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider"/>
+
+ <ListView
+ android:visibility="gone"
+ android:id="@android:id/list"
+ android:drawSelectorOnTop="false"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:scrollbarStyle="outsideOverlay" />
+
+ <LinearLayout
+ android:id="@+id/loading_container"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="visible"
+ android:gravity="center">
+
+ <ProgressBar
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/loading"
+ android:paddingTop="4dip"
+ android:singleLine="true" />
+
+ </LinearLayout>
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/s_layout.xml b/app/src/main/res/layout/s_layout.xml
new file mode 100644
index 00000000..d5717a5b
--- /dev/null
+++ b/app/src/main/res/layout/s_layout.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:id="@+id/buttontest"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="A"/>
+
+</ScrollView>
diff --git a/app/src/main/res/menu/allowed_apps.xml b/app/src/main/res/menu/allowed_apps.xml
new file mode 100644
index 00000000..20eb91e1
--- /dev/null
+++ b/app/src/main/res/menu/allowed_apps.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-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
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/app_search_widget"
+ app:actionViewClass="android.widget.SearchView"
+ android:icon="@drawable/ic_search_white_24dp"
+ app:showAsAction="always"
+ android:title="@string/Search"/>
+</menu> \ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index d8873017..a8cdb28e 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -35,4 +35,6 @@
<color name="colorActionBarTitleFont">@color/white</color>
<color name="colorActionBarSubtitleFont">@color/black800</color>
+ <color name="colorWarning">#B33A3A</color>
+
</resources>
diff --git a/app/src/main/res/values/strings-icsopenvpn.xml b/app/src/main/res/values/strings-icsopenvpn.xml
index b390ecec..b552715a 100755
--- a/app/src/main/res/values/strings-icsopenvpn.xml
+++ b/app/src/main/res/values/strings-icsopenvpn.xml
@@ -486,5 +486,4 @@
<string name="external_authenticator">External Authenticator</string>
<string name="configure">Configure</string>
<string name="extauth_not_configured">External Authneticator not configured</string>
-
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1b22592a..e685cff5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -32,6 +32,7 @@
<string name="password_mismatch">Passwords do not match</string>
<string name="user_message">User message</string>
<string name="about_fragment_title">About</string>
+ <string name="exclude_apps_fragment_title">Exclude apps from VPN</string>
<string name="error_srp_math_error_user_message">Try again: Server math error</string>
<string name="error_bad_user_password_user_message">Incorrect username or password</string>
<string name="error_not_valid_password_user_message">It must be at least 8 characters long</string>
@@ -110,4 +111,6 @@
<string name="donate_message">LEAP depends on donations and grants. Please donate today if you value secure communication that is easy for both the end-user and the service provider.</string>
<string name="donate_button_remind_later">Remind me later</string>
<string name="donate_button_donate">Donate</string>
+ <string name="warning_exclude_apps_message">Be careful of excluding apps from VPN. This will reveal your identity and compromise your security.</string>
+
</resources>
diff --git a/app/src/main/res/values/untranslatable.xml b/app/src/main/res/values/untranslatable.xml
index a92cd176..cbae03fd 100644
--- a/app/src/main/res/values/untranslatable.xml
+++ b/app/src/main/res/values/untranslatable.xml
@@ -2,13 +2,13 @@
<resources>
<string name="notifcation_title_bitmask" translatable="false">%s - %s</string>
<string name="copyright_leapgui" translatable="false">Copyright 2012-2019\nLEAP Encryption Access Project &lt;info@leap.se></string>
- <string name="opevpn_copyright" translatable="false">Copyright © 2002–2019 OpenVPN Technologies, Inc. &lt;sales@openvpn.net>\n
+ <string name="opevpn_copyright" translatable="false">Copyright ? 2002?2019 OpenVPN Technologies, Inc. &lt;sales@openvpn.net>\n
"OpenVPN" is a trademark of OpenVPN Technologies, Inc.</string>
- <string name="lzo_copyright" translatable="false">Copyright © 1996 – 2011 Markus Franz Xaver Johannes Oberhumer</string>
+ <string name="lzo_copyright" translatable="false">Copyright ? 1996 ? 2011 Markus Franz Xaver Johannes Oberhumer</string>
<string name="copyright_openssl" translatable="false"> Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.\n\n
This product includes cryptographic software written by Eric Young (eay@cryptsoft.com)\n
- Copyright © 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.</string>
- <string name="copyright_okhttp" translatable="false">Copyright © 2019 Square, Inc.</string>
+ Copyright ? 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.</string>
+ <string name="copyright_okhttp" translatable="false">Copyright ? 2019 Square, Inc.</string>
<string name="okhttp" translatable="false">OkHttp</string>
<string name="openvpn" translatable="false">OpenVPN</string>
<string name="lzo" translatable="false">LZO</string>
@@ -23,14 +23,14 @@
<string name="copyright_openvpn3" translatable="false">GNU AFFERO GENERAL PUBLIC LICENSE\n
Version 3, 19 November 2007</string>
<string name="unknown_state" translatable="false">Unknown state</string>
- <string name="copyright_blinktgui" translatable="false">Copyright 2012–2019 Arne Schwabe &lt;arne@rfc2549.org></string>
+ <string name="copyright_blinktgui" translatable="false">Copyright 2012?2019 Arne Schwabe &lt;arne@rfc2549.org></string>
<string name="defaultserver" translatable="false">openvpn.uni-paderborn.de</string>
<string name="defaultport" translatable="false">1194</string>
<string name="copyright_file_dialog" translatable="false">File Dialog based on work by Alexander Ponomarev</string>
<string name="file_dialog" translatable="false">File Dialog</string>
<string name="permission_description" translatable="false">Allows another app to control OpenVPN</string>
<string name="bouncy_castle" translatable="false">Bouncy Castle Crypto APIs</string>
- <string name="copyright_bouncycastle" translatable="false">Copyright © 2000–2012 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)</string>
+ <string name="copyright_bouncycastle" translatable="false">Copyright ? 2000?2012 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)</string>
<string name="state_user_vpn_permission" translatable="false">Waiting for user permission to use VPN API</string>
<string name="state_user_vpn_password" translatable="false">Waiting for user VPN password</string>
<string name="state_user_vpn_password_cancelled" translatable="false">VPN password input dialog cancelled</string>
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java
index 6d858d39..2f5ae9b6 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java
@@ -1,5 +1,32 @@
package se.leap.bitmaskclient.eip;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.Display;
+
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
@@ -14,7 +41,12 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import se.leap.bitmaskclient.Provider;
@@ -74,7 +106,7 @@ public class GatewaySelectorTest {
for (int i = 0; i < gateways.length(); i++) {
JSONObject gw = gateways.getJSONObject(i);
JSONObject secrets = secretsConfiguration();
- Gateway aux = new Gateway(eipDefinition, secrets, gw);
+ Gateway aux = new Gateway(eipDefinition, secrets, gw, null);
gatewayList.add(aux);
}