Commit 302f4108 authored by akuma's avatar akuma
Browse files

Select Apps option

parent 303dd2a0
Pipeline #26240 canceled with stages
......@@ -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;
......
......@@ -59,6 +59,8 @@ 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.SelectAppsFragment;
import se.leap.bitmaskclient.fragments.Settings_Allowed_Apps;
import static android.content.Context.MODE_PRIVATE;
import static se.leap.bitmaskclient.BitmaskApp.getRefWatcher;
......@@ -74,6 +76,7 @@ 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.donate_title;
......@@ -273,6 +276,7 @@ public class NavigationDrawerFragment extends Fragment {
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(about_fragment_title), R.drawable.ic_about_36, SELECT_APPS));
}
private ActionBar setupActionBar() {
......@@ -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 Settings_Allowed_Apps();
setActionBarTitle(about_fragment_title);
break;
default:
break;
}
......
......@@ -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,12 @@ 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;
/**
* Gateway provides objects defining gateways and their metadata.
......@@ -52,7 +58,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 +68,11 @@ public class Gateway {
mName = locationAsName(eip_definition);
mVpnProfile = createVPNProfile();
System.out.println("###########" + mName + "###########");
mVpnProfile.mName = mName;
SharedPreferences allow_apps = context.getSharedPreferences("BITMASK", Context.MODE_MULTI_PROCESS);
Please register or sign in to reply
mVpnProfile.mAllowedAppsVpn = new HashSet<String>(allow_apps.getStringSet("ALLOW_APPS", new HashSet<String>()));
}
private JSONObject getGeneralConfiguration(JSONObject eip_definition) {
......
......@@ -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, context);
if (!gateways.contains(aux)) {
addGateway(aux);
}
......
/*
* 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.EipSetupListener;
import se.leap.bitmaskclient.EipSetupObserver;
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<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.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<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);
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 = new HashSet<String>(allow_apps.getStringSet("ALLOW_APPS", new HashSet<String>()));
// /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);
}
}
<?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
<?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
<?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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/actionBarSize"
android:background="@drawable/bg_switchbar"
android:paddingStart="@dimen/switchbar_pad"
android:elevation="1dp"
android:paddingEnd="@dimen/switchbar_pad"
tools:ignore="NewApi">
<Switch
android:id="@+id/default_allow"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/default_allow_text"
style="@android:style/TextAppearance.Medium.Inverse"
tools:text="@string/vpn_disallow_radio"