2015-11-04 22:44:17 +00:00
|
|
|
package eu.faircode.netguard;
|
|
|
|
|
|
|
|
/*
|
|
|
|
This file is part of NetGuard.
|
|
|
|
|
|
|
|
NetGuard is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
NetGuard is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with NetGuard. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Copyright 2015 by Marcel Bokhorst (M66B)
|
|
|
|
*/
|
|
|
|
|
2015-11-10 14:32:59 +00:00
|
|
|
import android.app.admin.DevicePolicyManager;
|
|
|
|
import android.content.ComponentName;
|
2015-11-05 10:26:21 +00:00
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
2015-11-04 22:44:17 +00:00
|
|
|
import android.content.SharedPreferences;
|
2015-11-05 10:26:21 +00:00
|
|
|
import android.os.AsyncTask;
|
2015-11-04 22:44:17 +00:00
|
|
|
import android.os.Bundle;
|
2015-11-06 22:49:03 +00:00
|
|
|
import android.preference.Preference;
|
2015-11-04 22:44:17 +00:00
|
|
|
import android.preference.PreferenceManager;
|
2015-11-06 22:49:03 +00:00
|
|
|
import android.preference.PreferenceScreen;
|
2015-11-04 22:44:17 +00:00
|
|
|
import android.support.v7.app.AppCompatActivity;
|
2015-11-05 10:26:21 +00:00
|
|
|
import android.util.Log;
|
|
|
|
import android.util.Xml;
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
|
|
|
import org.xml.sax.Attributes;
|
|
|
|
import org.xml.sax.InputSource;
|
|
|
|
import org.xml.sax.SAXException;
|
|
|
|
import org.xml.sax.XMLReader;
|
|
|
|
import org.xml.sax.helpers.DefaultHandler;
|
|
|
|
import org.xmlpull.v1.XmlSerializer;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
import javax.xml.parsers.ParserConfigurationException;
|
|
|
|
import javax.xml.parsers.SAXParserFactory;
|
2015-11-04 22:44:17 +00:00
|
|
|
|
|
|
|
public class ActivitySettings extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
2015-11-05 10:26:21 +00:00
|
|
|
private static final String TAG = "NetGuard.Settings";
|
|
|
|
|
2015-11-10 13:41:32 +00:00
|
|
|
private boolean unlocked = false;
|
|
|
|
public static final String EXTRA_UNLOCKED = "unlocked";
|
|
|
|
|
2015-11-06 22:49:03 +00:00
|
|
|
private static final int REQUEST_EXPORT = 1;
|
|
|
|
private static final int REQUEST_IMPORT = 2;
|
|
|
|
private static final Intent INTENT_VPN_SETTINGS = new Intent("android.net.vpn.SETTINGS");
|
2015-11-05 10:26:21 +00:00
|
|
|
|
2015-11-04 22:44:17 +00:00
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
|
|
|
setTheme(prefs.getBoolean("dark_theme", false) ? R.style.AppThemeDark : R.style.AppTheme);
|
|
|
|
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
2015-11-10 13:41:32 +00:00
|
|
|
unlocked = getIntent().getBooleanExtra(EXTRA_UNLOCKED, false);
|
|
|
|
|
2015-11-04 22:44:17 +00:00
|
|
|
getFragmentManager().beginTransaction().replace(android.R.id.content, new FragmentSettings()).commit();
|
2015-11-10 13:55:20 +00:00
|
|
|
getSupportActionBar().setTitle(R.string.menu_settings);
|
2015-11-04 22:44:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
2015-11-10 13:41:32 +00:00
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
|
|
|
prefs.unregisterOnSharedPreferenceChangeListener(this);
|
2015-11-04 22:44:17 +00:00
|
|
|
super.onDestroy();
|
|
|
|
}
|
|
|
|
|
2015-11-06 22:49:03 +00:00
|
|
|
public void setup(PreferenceScreen screen) {
|
|
|
|
Preference pref_export = screen.findPreference("export");
|
|
|
|
pref_export.setEnabled(getIntentCreateDocument().resolveActivity(getPackageManager()) != null);
|
|
|
|
pref_export.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
|
|
|
@Override
|
|
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
|
|
startActivityForResult(getIntentCreateDocument(), ActivitySettings.REQUEST_EXPORT);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Preference pref_import = screen.findPreference("import");
|
|
|
|
pref_import.setEnabled(getIntentCreateDocument().resolveActivity(getPackageManager()) != null);
|
|
|
|
pref_import.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
|
|
|
@Override
|
|
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
|
|
startActivityForResult(getIntentOpenDocument(), ActivitySettings.REQUEST_IMPORT);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Preference pref_vpn = screen.findPreference("vpn");
|
2015-11-10 09:30:37 +00:00
|
|
|
if (Util.isDebuggable(this)) {
|
|
|
|
pref_vpn.setEnabled(INTENT_VPN_SETTINGS.resolveActivity(this.getPackageManager()) != null);
|
|
|
|
pref_vpn.setIntent(INTENT_VPN_SETTINGS);
|
|
|
|
} else
|
|
|
|
screen.removePreference(pref_vpn);
|
2015-11-06 22:49:03 +00:00
|
|
|
|
2015-11-10 13:41:32 +00:00
|
|
|
if (!unlocked)
|
|
|
|
for (int i = 0; i < screen.getPreferenceCount(); i++)
|
|
|
|
screen.getPreference(i).setEnabled(false);
|
|
|
|
|
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
|
|
|
prefs.registerOnSharedPreferenceChangeListener(this);
|
2015-11-06 22:49:03 +00:00
|
|
|
}
|
|
|
|
|
2015-11-04 22:44:17 +00:00
|
|
|
@Override
|
|
|
|
public void onSharedPreferenceChanged(SharedPreferences prefs, String name) {
|
|
|
|
if ("whitelist_wifi".equals(name))
|
|
|
|
SinkholeService.reload("wifi", this);
|
|
|
|
|
|
|
|
else if ("whitelist_other".equals(name))
|
|
|
|
SinkholeService.reload("other", this);
|
|
|
|
|
|
|
|
else if ("whitelist_roaming".equals(name))
|
|
|
|
SinkholeService.reload("other", this);
|
|
|
|
|
2015-11-05 16:21:43 +00:00
|
|
|
else if ("manage_system".equals(name))
|
2015-11-04 22:44:17 +00:00
|
|
|
SinkholeService.reload(null, this);
|
|
|
|
|
2015-11-10 14:32:59 +00:00
|
|
|
else if ("credentials".equals(name)) {
|
|
|
|
ComponentName component = new ComponentName(this, DeviceAdministratorReceiver.class);
|
|
|
|
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
|
|
|
|
if (prefs.getBoolean(name, false) && !dpm.isAdminActive(component)) {
|
|
|
|
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
|
|
|
|
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, component);
|
|
|
|
if (intent.resolveActivity(getPackageManager()) != null)
|
|
|
|
startActivity(intent);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if ("dark_theme".equals(name))
|
2015-11-04 22:44:17 +00:00
|
|
|
recreate();
|
|
|
|
}
|
2015-11-05 10:26:21 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
|
|
|
|
Log.i(TAG, "onActivityResult request=" + requestCode + " result=" + requestCode + " ok=" + (resultCode == RESULT_OK));
|
|
|
|
if (requestCode == REQUEST_EXPORT) {
|
|
|
|
if (resultCode == RESULT_OK && data != null)
|
|
|
|
handleExport(data);
|
|
|
|
|
|
|
|
} else if (requestCode == REQUEST_IMPORT) {
|
|
|
|
if (resultCode == RESULT_OK && data != null)
|
|
|
|
handleImport(data);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
Log.w(TAG, "Unknown activity result request=" + requestCode);
|
|
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleExport(final Intent data) {
|
|
|
|
new AsyncTask<Object, Object, Throwable>() {
|
|
|
|
@Override
|
|
|
|
protected Throwable doInBackground(Object... objects) {
|
|
|
|
OutputStream out = null;
|
|
|
|
try {
|
|
|
|
out = getContentResolver().openOutputStream(data.getData());
|
|
|
|
Log.i(TAG, "Writing URI=" + data.getData());
|
|
|
|
xmlExport(out);
|
|
|
|
return null;
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
|
|
|
return ex;
|
|
|
|
} finally {
|
|
|
|
if (out != null)
|
|
|
|
try {
|
|
|
|
out.close();
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onPostExecute(Throwable ex) {
|
|
|
|
if (ex == null)
|
|
|
|
Toast.makeText(ActivitySettings.this, R.string.msg_completed, Toast.LENGTH_LONG).show();
|
|
|
|
else
|
|
|
|
Toast.makeText(ActivitySettings.this, ex.toString(), Toast.LENGTH_LONG).show();
|
|
|
|
}
|
|
|
|
}.execute();
|
|
|
|
}
|
|
|
|
|
2015-11-06 22:49:03 +00:00
|
|
|
private static Intent getIntentCreateDocument() {
|
|
|
|
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
|
|
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
|
|
intent.setType("text/xml");
|
|
|
|
intent.putExtra(Intent.EXTRA_TITLE, "netguard.xml");
|
|
|
|
return intent;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Intent getIntentOpenDocument() {
|
|
|
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
|
|
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
|
|
intent.setType("text/xml");
|
|
|
|
return intent;
|
|
|
|
}
|
|
|
|
|
2015-11-05 10:26:21 +00:00
|
|
|
private void handleImport(final Intent data) {
|
|
|
|
new AsyncTask<Object, Object, Throwable>() {
|
|
|
|
@Override
|
|
|
|
protected Throwable doInBackground(Object... objects) {
|
|
|
|
InputStream in = null;
|
|
|
|
try {
|
|
|
|
in = getContentResolver().openInputStream(data.getData());
|
|
|
|
Log.i(TAG, "Reading URI=" + data.getData());
|
|
|
|
xmlImport(in);
|
|
|
|
return null;
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
|
|
|
return ex;
|
|
|
|
} finally {
|
|
|
|
if (in != null)
|
|
|
|
try {
|
|
|
|
in.close();
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onPostExecute(Throwable ex) {
|
2015-11-08 11:30:39 +00:00
|
|
|
if (ex == null)
|
2015-11-05 10:26:21 +00:00
|
|
|
Toast.makeText(ActivitySettings.this, R.string.msg_completed, Toast.LENGTH_LONG).show();
|
2015-11-08 11:30:39 +00:00
|
|
|
else
|
2015-11-05 10:26:21 +00:00
|
|
|
Toast.makeText(ActivitySettings.this, ex.toString(), Toast.LENGTH_LONG).show();
|
|
|
|
}
|
|
|
|
}.execute();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void xmlExport(OutputStream out) throws IOException {
|
|
|
|
XmlSerializer serializer = Xml.newSerializer();
|
|
|
|
serializer.setOutput(out, "UTF-8");
|
|
|
|
serializer.startDocument(null, true);
|
|
|
|
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
|
|
|
|
serializer.startTag(null, "netguard");
|
|
|
|
|
|
|
|
serializer.startTag(null, "application");
|
|
|
|
xmlExport(PreferenceManager.getDefaultSharedPreferences(this), serializer);
|
|
|
|
serializer.endTag(null, "application");
|
|
|
|
|
|
|
|
serializer.startTag(null, "wifi");
|
|
|
|
xmlExport(getSharedPreferences("wifi", Context.MODE_PRIVATE), serializer);
|
|
|
|
serializer.endTag(null, "wifi");
|
|
|
|
|
|
|
|
serializer.startTag(null, "mobile");
|
|
|
|
xmlExport(getSharedPreferences("other", Context.MODE_PRIVATE), serializer);
|
|
|
|
serializer.endTag(null, "mobile");
|
|
|
|
|
|
|
|
serializer.startTag(null, "unused");
|
|
|
|
xmlExport(getSharedPreferences("unused", Context.MODE_PRIVATE), serializer);
|
|
|
|
serializer.endTag(null, "unused");
|
|
|
|
|
|
|
|
serializer.endTag(null, "netguard");
|
|
|
|
serializer.endDocument();
|
|
|
|
serializer.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void xmlExport(SharedPreferences prefs, XmlSerializer serializer) throws IOException {
|
|
|
|
Map<String, ?> settings = prefs.getAll();
|
|
|
|
for (String key : settings.keySet()) {
|
|
|
|
Object value = settings.get(key);
|
2015-11-08 12:05:55 +00:00
|
|
|
|
|
|
|
if ("imported".equals(key))
|
|
|
|
continue;
|
|
|
|
|
2015-11-05 10:26:21 +00:00
|
|
|
if (value instanceof Boolean) {
|
|
|
|
serializer.startTag(null, "setting");
|
|
|
|
serializer.attribute(null, "key", key);
|
|
|
|
serializer.attribute(null, "type", "boolean");
|
|
|
|
serializer.attribute(null, "value", value.toString());
|
|
|
|
serializer.endTag(null, "setting");
|
2015-11-08 12:05:55 +00:00
|
|
|
|
2015-11-05 10:26:21 +00:00
|
|
|
} else
|
|
|
|
Log.e(TAG, "Unknown key=" + key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void xmlImport(InputStream in) throws IOException, SAXException, ParserConfigurationException {
|
2015-11-08 11:30:39 +00:00
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
|
|
|
prefs.edit().putBoolean("enabled", false).apply();
|
|
|
|
SinkholeService.stop(this);
|
|
|
|
|
2015-11-05 10:26:21 +00:00
|
|
|
XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
|
|
|
|
XmlImportHandler handler = new XmlImportHandler();
|
|
|
|
reader.setContentHandler(handler);
|
|
|
|
reader.parse(new InputSource(in));
|
|
|
|
|
2015-11-08 11:30:39 +00:00
|
|
|
xmlImport(handler.application, prefs);
|
2015-11-05 10:26:21 +00:00
|
|
|
xmlImport(handler.wifi, getSharedPreferences("wifi", Context.MODE_PRIVATE));
|
|
|
|
xmlImport(handler.mobile, getSharedPreferences("other", Context.MODE_PRIVATE));
|
|
|
|
xmlImport(handler.unused, getSharedPreferences("unused", Context.MODE_PRIVATE));
|
2015-11-08 11:30:39 +00:00
|
|
|
xmlImport(handler.roaming, getSharedPreferences("roaming", Context.MODE_PRIVATE));
|
2015-11-08 12:05:55 +00:00
|
|
|
|
|
|
|
// Refresh UI
|
|
|
|
prefs.edit().putBoolean("imported", true).apply();
|
2015-11-05 10:26:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void xmlImport(Map<String, Object> settings, SharedPreferences prefs) {
|
|
|
|
SharedPreferences.Editor editor = prefs.edit();
|
|
|
|
|
2015-11-08 11:30:39 +00:00
|
|
|
// Clear existing setting
|
2015-11-05 10:26:21 +00:00
|
|
|
for (String key : prefs.getAll().keySet())
|
2015-11-08 11:30:39 +00:00
|
|
|
if (!"enabled".equals(key))
|
|
|
|
editor.remove(key);
|
2015-11-05 10:26:21 +00:00
|
|
|
|
2015-11-08 11:30:39 +00:00
|
|
|
// Apply new settings
|
2015-11-05 10:26:21 +00:00
|
|
|
for (String key : settings.keySet()) {
|
|
|
|
Object value = settings.get(key);
|
|
|
|
if (value instanceof Boolean)
|
|
|
|
editor.putBoolean(key, (Boolean) value);
|
|
|
|
else
|
|
|
|
Log.e(TAG, "Unknown type=" + value.getClass());
|
|
|
|
}
|
|
|
|
|
|
|
|
editor.apply();
|
|
|
|
}
|
|
|
|
|
|
|
|
private class XmlImportHandler extends DefaultHandler {
|
2015-11-08 11:30:39 +00:00
|
|
|
public boolean enabled = false;
|
2015-11-05 10:26:21 +00:00
|
|
|
public Map<String, Object> application = new HashMap<>();
|
|
|
|
public Map<String, Object> wifi = new HashMap<>();
|
|
|
|
public Map<String, Object> mobile = new HashMap<>();
|
|
|
|
public Map<String, Object> unused = new HashMap<>();
|
2015-11-08 11:30:39 +00:00
|
|
|
public Map<String, Object> roaming = new HashMap<>();
|
2015-11-05 10:26:21 +00:00
|
|
|
private Map<String, Object> current = null;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
|
|
|
if (qName.equals("netguard"))
|
|
|
|
; // Ignore
|
|
|
|
|
|
|
|
else if (qName.equals("application"))
|
|
|
|
current = application;
|
|
|
|
|
|
|
|
else if (qName.equals("wifi"))
|
|
|
|
current = wifi;
|
|
|
|
|
|
|
|
else if (qName.equals("mobile"))
|
|
|
|
current = mobile;
|
|
|
|
|
|
|
|
else if (qName.equals("unused"))
|
|
|
|
current = unused;
|
|
|
|
|
2015-11-08 11:30:39 +00:00
|
|
|
else if (qName.equals("roaming"))
|
|
|
|
roaming = unused;
|
|
|
|
|
2015-11-05 10:26:21 +00:00
|
|
|
else if (qName.equals("setting")) {
|
|
|
|
String key = attributes.getValue("key");
|
|
|
|
String type = attributes.getValue("type");
|
|
|
|
String value = attributes.getValue("value");
|
|
|
|
|
|
|
|
if (current == null)
|
|
|
|
Log.e(TAG, "No current key=" + key);
|
|
|
|
else {
|
2015-11-08 11:30:39 +00:00
|
|
|
if ("enabled".equals(key))
|
|
|
|
enabled = Boolean.parseBoolean(value);
|
|
|
|
else {
|
|
|
|
if ("boolean".equals(type))
|
|
|
|
current.put(key, Boolean.parseBoolean(value));
|
|
|
|
else
|
|
|
|
Log.e(TAG, "Unknown type key=" + key);
|
|
|
|
}
|
2015-11-05 10:26:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else
|
|
|
|
Log.e(TAG, "Unknown element qname=" + qName);
|
|
|
|
}
|
|
|
|
}
|
2015-11-04 22:44:17 +00:00
|
|
|
}
|