From 2e1c94d3f51dc6d667435b2a2bbd81a036d57bae Mon Sep 17 00:00:00 2001 From: akuma Date: Sun, 8 Sep 2019 20:40:29 +0200 Subject: New icon and text for Excluded Apps. Using PreferenceHelper. Test done. --- .../androidTest/legacy/TestGatewaysManager.java | 6 +- .../main/java/se/leap/bitmaskclient/Constants.java | 1 + .../drawer/NavigationDrawerFragment.java | 11 +- .../java/se/leap/bitmaskclient/eip/Gateway.java | 11 +- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 2 +- .../fragments/ExcludeAppsFragment.java | 329 +++++++++++++++++++ .../fragments/Settings_Allowed_Apps.java | 364 --------------------- .../leap/bitmaskclient/utils/PreferenceHelper.java | 19 ++ .../ic_shield_remove_grey600_36dp.png | Bin 0 -> 1628 bytes .../ic_shield_remove_grey600_36dp.png | Bin 0 -> 1192 bytes .../ic_shield_remove_grey600_36dp.png | Bin 0 -> 1930 bytes .../ic_shield_remove_grey600_36dp.png | Bin 0 -> 2902 bytes .../ic_shield_remove_grey600_36dp.png | Bin 0 -> 3686 bytes app/src/main/res/layout/allowed_vpn_apps.xml | 37 +-- app/src/main/res/values/colors.xml | 2 + app/src/main/res/values/strings-icsopenvpn.xml | 1 - app/src/main/res/values/strings.xml | 4 +- .../bitmaskclient/eip/GatewaySelectorTest.java | 34 +- 18 files changed, 416 insertions(+), 405 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/fragments/ExcludeAppsFragment.java delete mode 100644 app/src/main/java/se/leap/bitmaskclient/fragments/Settings_Allowed_Apps.java create mode 100644 app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png 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/drawer/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java index 99dfb890..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,7 +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.Settings_Allowed_Apps; +import se.leap.bitmaskclient.fragments.ExcludeAppsFragment; import static android.content.Context.MODE_PRIVATE; import static se.leap.bitmaskclient.BitmaskApp.getRefWatcher; @@ -78,11 +78,10 @@ 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.allow_apps_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; -import static se.leap.bitmaskclient.R.string.allow_apps_fragment_title; import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.utils.PreferenceHelper.getProviderName; import static se.leap.bitmaskclient.utils.PreferenceHelper.getSaveBattery; @@ -272,12 +271,12 @@ 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)); } settingsListAdapter.addItem(getSimpleTextInstance(getContext(), getString(about_fragment_title), R.drawable.ic_about_36, ABOUT)); - settingsListAdapter.addItem(getSimpleTextInstance(getContext(), getString(allow_apps_fragment_title), R.drawable.ic_about_36, SELECT_APPS)); } private ActionBar setupActionBar() { @@ -500,8 +499,8 @@ public class NavigationDrawerFragment extends Fragment { startActivity(browserIntent); break; case SELECT_APPS: - fragment = new Settings_Allowed_Apps(); - setActionBarTitle(allow_apps_fragment_title); + 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 77666378..09b33845 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -32,6 +32,7 @@ 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. @@ -71,8 +72,14 @@ public class Gateway { System.out.println("###########" + mName + "###########"); mVpnProfile.mName = mName; - SharedPreferences allow_apps = context.getSharedPreferences("BITMASK", Context.MODE_MULTI_PROCESS); - mVpnProfile.mAllowedAppsVpn = new HashSet(allow_apps.getStringSet("ALLOW_APPS", new HashSet())); + Set 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 8edf81ef..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, context); + 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 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 mPackages; + private final LayoutInflater mInflater; + private final PackageManager mPm; + private ItemFilter mFilter = new ItemFilter(); + private Vector 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 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) 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 installedPackages = mPm.getInstalledApplications(PackageManager.GET_META_DATA); + + // Remove apps not using Internet + + int androidSystemUid = 0; + ApplicationInfo system = null; + Vector apps = new Vector(); + + 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/fragments/Settings_Allowed_Apps.java b/app/src/main/java/se/leap/bitmaskclient/fragments/Settings_Allowed_Apps.java deleted file mode 100644 index a563978a..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/fragments/Settings_Allowed_Apps.java +++ /dev/null @@ -1,364 +0,0 @@ -/* - * 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.Switch; -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; - -/** - * Created by arne on 16.11.14. - */ -public class Settings_Allowed_Apps extends Fragment implements AdapterView.OnItemClickListener, CompoundButton.OnCheckedChangeListener, View.OnClickListener { - private ListView mListView; - private VpnProfile mProfile; - private TextView mDefaultAllowTextView; - private PackageAdapter mListAdapter; - - private SharedPreferences allow_apps; - private SharedPreferences.Editor allow_apps_editor; - private Set 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.appSize = (TextView) convertView.findViewById(R.id.app_size); - //holder.disabled = (TextView) convertView.findViewById(R.id.app_disabled); - 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); - //Log.d("eneko", this.getContext().getSharedPreferences("BITMASK", Context.MODE_MULTI_PROCESS).getString("ALLOW_APPS", "")); - - apps.remove(packageName); - } - allow_apps_editor.clear(); - allow_apps_editor.putStringSet("ALLOW_APPS", apps); - allow_apps_editor.apply(); - } - - - class PackageAdapter extends BaseAdapter implements Filterable { - private Vector mPackages; - private final LayoutInflater mInflater; - private final PackageManager mPm; - private ItemFilter mFilter = new ItemFilter(); - private Vector 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 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) 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 installedPackages = mPm.getInstalledApplications(PackageManager.GET_META_DATA); - - // Remove apps not using Internet - - int androidSystemUid = 0; - ApplicationInfo system = null; - Vector apps = new Vector(); - - 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); - convertView = viewHolder.rootView; - 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(Settings_Allowed_Apps.this); - viewHolder.checkBox.setChecked(apps.contains(mInfo.packageName)); - - - // viewHolder.checkBox.setChecked(mProfile.mAllowedAppsVpn.contains(mInfo.packageName)); - return viewHolder.rootView; - } - - @Override - public Filter getFilter() { - return mFilter; - } - } - - @Override - public void onResume() { - super.onResume(); -// changeDisallowText(mProfile.mAllowedAppsVpnAreDisallowed); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - allow_apps = this.getContext().getSharedPreferences("BITMASK", Context.MODE_MULTI_PROCESS); - allow_apps_editor = allow_apps.edit(); - apps = allow_apps.getStringSet("ALLOW_APPS", new HashSet()); - -// /String profileUuid = getArguments().getString(getActivity().getPackageName() + ".profileUUID"); -// mProfile = EipSetupObserver.getProfile(); -// getActivity().setTitle(getString(R.string.edit_profile_title, mProfile.getName())); - 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); - -// mDefaultAllowTextView = (TextView) v.findViewById(R.id.default_allow_text); - - -// Switch vpnOnDefaultSwitch = (Switch) v.findViewById(R.id.default_allow); -// -// vpnOnDefaultSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { -// @Override -// public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { -// -// changeDisallowText(isChecked); -// mProfile.mAllowedAppsVpnAreDisallowed = isChecked; -// } -// }); - -// vpnOnDefaultSwitch.setChecked(mProfile.mAllowedAppsVpnAreDisallowed); - - mListView = (ListView) 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; - } - - private void changeDisallowText(boolean selectedAreDisallowed) { - if (selectedAreDisallowed) - mDefaultAllowTextView.setText(R.string.vpn_disallow_radio); - else - mDefaultAllowTextView.setText(R.string.vpn_allow_radio); - } -} 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 apps) { + SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + SharedPreferences.Editor prefsedit = prefs.edit(); + prefsedit.putStringSet(EXCLUDED_APPS, apps); + prefsedit.apply(); + } + + public static Set 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_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 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png 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 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png 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 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png 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 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png 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 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png differ diff --git a/app/src/main/res/layout/allowed_vpn_apps.xml b/app/src/main/res/layout/allowed_vpn_apps.xml index 93327944..1219da54 100644 --- a/app/src/main/res/layout/allowed_vpn_apps.xml +++ b/app/src/main/res/layout/allowed_vpn_apps.xml @@ -9,33 +9,20 @@ android:layout_width="match_parent" tools:ignore="RtlCompat" android:layout_height="match_parent"> - + - - @color/white @color/black800 + #B33A3A + 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 @@ External Authenticator Configure External Authneticator not configured - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e794c75c..e685cff5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,7 +32,7 @@ Passwords do not match User message About - Select Apps + Exclude apps from VPN Try again: Server math error Incorrect username or password It must be at least 8 characters long @@ -111,4 +111,6 @@ 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. Remind me later Donate + Be careful of excluding apps from VPN. This will reveal your identity and compromise your security. + 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); } -- cgit v1.2.3