diff options
author | cyberta <cyberta@riseup.net> | 2019-09-19 07:34:54 -0700 |
---|---|---|
committer | cyberta <cyberta@riseup.net> | 2019-09-19 07:34:54 -0700 |
commit | 7820e8c0819a10c5b4729678607681fcfe30cbae (patch) | |
tree | 43590440908ce85ef286487bb5c44155b3de1f8e | |
parent | 303dd2a0e498fac87144b2d7ac930b27fe1bc7e8 (diff) | |
parent | 2e1c94d3f51dc6d667435b2a2bbd81a036d57bae (diff) |
Merge branch 'master' into 'master'
[New Feature] Option for excluding apps from VPN
See merge request leap/bitmask_android!93
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 Binary files differnew file mode 100755 index 00000000..bbfbc96c --- /dev/null +++ b/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png 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 Binary files differnew file mode 100644 index 00000000..98dec84c --- /dev/null +++ b/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png 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 Binary files differnew file mode 100755 index 00000000..faefc59c --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png 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 Binary files differnew file mode 100644 index 00000000..d4b61030 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png 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 Binary files differnew file mode 100755 index 00000000..bfc3e393 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png 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 Binary files differnew file mode 100644 index 00000000..3eae1fdc --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png 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 Binary files differnew file mode 100755 index 00000000..abbb9895 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png 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 Binary files differnew file mode 100644 index 00000000..c6761744 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png 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 Binary files differnew file mode 100755 index 00000000..dd5adfc7 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png 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 Binary files differnew file mode 100644 index 00000000..ad08be94 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png 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 <info@leap.se></string> - <string name="opevpn_copyright" translatable="false">Copyright © 2002–2019 OpenVPN Technologies, Inc. <sales@openvpn.net>\n + <string name="opevpn_copyright" translatable="false">Copyright ? 2002?2019 OpenVPN Technologies, Inc. <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 <arne@rfc2549.org></string> + <string name="copyright_blinktgui" translatable="false">Copyright 2012?2019 Arne Schwabe <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); } |