App Filter
This commit is contained in:
parent
1da2f456b8
commit
ca34f79307
@ -44,6 +44,7 @@ dependencies {
|
|||||||
implementation 'androidx.percentlayout:percentlayout:1.0.0'
|
implementation 'androidx.percentlayout:percentlayout:1.0.0'
|
||||||
implementation 'androidx.cardview:cardview:1.0.0'
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation 'com.google.android.material:material:1.0.0'
|
implementation 'com.google.android.material:material:1.0.0'
|
||||||
|
implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha03'
|
||||||
//DNS
|
//DNS
|
||||||
implementation 'org.pcap4j:pcap4j-core:1.7.4'
|
implementation 'org.pcap4j:pcap4j-core:1.7.4'
|
||||||
implementation 'org.pcap4j:pcap4j-packetfactory-static:1.7.4'
|
implementation 'org.pcap4j:pcap4j-packetfactory-static:1.7.4'
|
||||||
@ -51,8 +52,8 @@ dependencies {
|
|||||||
implementation 'com.google.code.gson:gson:2.8.5'
|
implementation 'com.google.code.gson:gson:2.8.5'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
|
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
|
||||||
//Analytics
|
//Analytics
|
||||||
implementation 'com.google.firebase:firebase-core:16.0.6'
|
implementation 'com.google.firebase:firebase-core:16.0.8'
|
||||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
|
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
android:configChanges="keyboard|keyboardHidden|screenLayout|uiMode|orientation|screenSize|smallestScreenSize"
|
android:configChanges="keyboard|keyboardHidden|screenLayout|uiMode|orientation|screenSize|smallestScreenSize"
|
||||||
android:theme="@style/AppTheme.NoActionBar">
|
android:theme="@style/AppTheme.NoActionBar">
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".activity.FilterAppProxyActivity" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -0,0 +1,195 @@
|
|||||||
|
package org.itxtech.daedalus.activity;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.itxtech.daedalus.Daedalus;
|
||||||
|
import org.itxtech.daedalus.R;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Daedalus Project
|
||||||
|
*
|
||||||
|
* @author iTX Technologies
|
||||||
|
* @link https://itxtech.org
|
||||||
|
* <p>
|
||||||
|
* This program 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.
|
||||||
|
*/
|
||||||
|
public class FilterAppProxyActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private RecyclerViewAdapter adapter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
if (Daedalus.isDarkTheme()) {
|
||||||
|
setTheme(R.style.AppTheme_Dark_NoActionBar);
|
||||||
|
}
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_filter_app);
|
||||||
|
Toolbar toolbar = findViewById(R.id.toolbar_filter);
|
||||||
|
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_clear);
|
||||||
|
RecyclerView recyclerView = findViewById(R.id.recyclerView_app_filter_list);
|
||||||
|
LinearLayoutManager manager = new LinearLayoutManager(this);
|
||||||
|
recyclerView.setLayoutManager(manager);
|
||||||
|
Drawable wrappedDrawable = DrawableCompat.wrap(Objects.requireNonNull(drawable));
|
||||||
|
DrawableCompat.setTint(wrappedDrawable, Color.WHITE);
|
||||||
|
toolbar.setNavigationIcon(drawable);
|
||||||
|
toolbar.setNavigationOnClickListener(v -> onBackPressed());
|
||||||
|
adapter = new RecyclerViewAdapter(getAppList());
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPostCreate(Bundle savedInstanceState) {
|
||||||
|
super.onPostCreate(savedInstanceState);
|
||||||
|
Toolbar toolbar = findViewById(R.id.toolbar_filter);
|
||||||
|
toolbar.setTitle(R.string.settings_app_filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
Daedalus.configurations.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AppObject {
|
||||||
|
private String app_name;
|
||||||
|
private String app_package_name;
|
||||||
|
private Drawable app_icon;
|
||||||
|
|
||||||
|
AppObject(String appName, String packageName, Drawable appIcon) {
|
||||||
|
this.app_name = appName;
|
||||||
|
this.app_package_name = packageName;
|
||||||
|
this.app_icon = appIcon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<AppObject> getAppList() {
|
||||||
|
PackageManager packageManager = getBaseContext().getPackageManager();
|
||||||
|
List<PackageInfo> packages = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
||||||
|
ArrayList<AppObject> appObjects = new ArrayList<>();
|
||||||
|
for (PackageInfo pkg : packages) {
|
||||||
|
appObjects.add(new AppObject(
|
||||||
|
pkg.applicationInfo.loadLabel(packageManager).toString(),
|
||||||
|
pkg.packageName,
|
||||||
|
pkg.applicationInfo.loadIcon(packageManager)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return appObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
|
||||||
|
private ArrayList<AppObject> appList;
|
||||||
|
@SuppressLint("UseSparseArrays")
|
||||||
|
private Map<Integer, Boolean> check_status = new HashMap<>();
|
||||||
|
|
||||||
|
RecyclerViewAdapter(ArrayList<AppObject> appObjects) {
|
||||||
|
appList = appObjects;
|
||||||
|
|
||||||
|
for (int i = 0; i < appObjects.size(); i++) {
|
||||||
|
if (Daedalus.configurations.getFilterAppObjects().contains(appObjects.get(i).app_package_name)) {
|
||||||
|
check_status.put(i, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_appview, parent, false);
|
||||||
|
return new RecyclerViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
|
||||||
|
String package_name = appList.get(position).app_package_name;
|
||||||
|
holder.app_name.setText(appList.get(position).app_name);
|
||||||
|
holder.app_icon.setImageDrawable(appList.get(position).app_icon);
|
||||||
|
holder.app_package_name = package_name;
|
||||||
|
holder.app_check.setOnCheckedChangeListener(null);
|
||||||
|
if (Daedalus.configurations.getFilterAppObjects().contains(package_name)) {
|
||||||
|
holder.app_check.setChecked(true);
|
||||||
|
//check_status.put(position, true);
|
||||||
|
}
|
||||||
|
holder.app_check.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
|
if (isChecked) {
|
||||||
|
check_status.put(position, true);
|
||||||
|
} else {
|
||||||
|
check_status.remove(position);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (check_status != null && check_status.containsKey(position)) {
|
||||||
|
holder.app_check.setChecked(true);
|
||||||
|
} else {
|
||||||
|
holder.app_check.setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return appList.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||||
|
private ImageView app_icon;
|
||||||
|
private TextView app_name;
|
||||||
|
private CheckBox app_check;
|
||||||
|
private String app_package_name;
|
||||||
|
|
||||||
|
RecyclerViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
app_icon = itemView.findViewById(R.id.app_icon);
|
||||||
|
app_name = itemView.findViewById(R.id.app_name);
|
||||||
|
app_check = itemView.findViewById(R.id.app_check);
|
||||||
|
itemView.setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (app_check.isChecked()) {
|
||||||
|
app_check.setChecked(false);
|
||||||
|
Daedalus.configurations.getFilterAppObjects().remove(app_package_name);
|
||||||
|
} else {
|
||||||
|
app_check.setChecked(true);
|
||||||
|
Daedalus.configurations.getFilterAppObjects().add(app_package_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,12 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.*;
|
import android.preference.*;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.itxtech.daedalus.Daedalus;
|
import org.itxtech.daedalus.Daedalus;
|
||||||
import org.itxtech.daedalus.R;
|
import org.itxtech.daedalus.R;
|
||||||
|
import org.itxtech.daedalus.activity.FilterAppProxyActivity;
|
||||||
import org.itxtech.daedalus.activity.MainActivity;
|
import org.itxtech.daedalus.activity.MainActivity;
|
||||||
import org.itxtech.daedalus.util.server.DNSServerHelper;
|
import org.itxtech.daedalus.util.server.DNSServerHelper;
|
||||||
|
|
||||||
@ -82,14 +85,28 @@ public class GlobalConfigFragment extends PreferenceFragment {
|
|||||||
SwitchPreference boot = (SwitchPreference) findPreference("settings_boot");
|
SwitchPreference boot = (SwitchPreference) findPreference("settings_boot");
|
||||||
boot.setEnabled(false);
|
boot.setEnabled(false);
|
||||||
boot.setChecked(false);
|
boot.setChecked(false);
|
||||||
|
SwitchPreference app_filter = (SwitchPreference) findPreference("settings_app_filter_switch");
|
||||||
|
app_filter.setEnabled(false);
|
||||||
|
app_filter.setChecked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SwitchPreference advanced = (SwitchPreference) findPreference("settings_advanced_switch");
|
SwitchPreference advanced = (SwitchPreference) findPreference("settings_advanced_switch");
|
||||||
advanced.setOnPreferenceChangeListener((preference, newValue) -> {
|
advanced.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
updateAdvancedOptions((boolean) newValue);
|
updateOptions((boolean) newValue, "settings_advanced");
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
SwitchPreference app_filter = (SwitchPreference) findPreference("settings_app_filter_switch");
|
||||||
|
app_filter.setOnPreferenceChangeListener((p, w) -> {
|
||||||
|
updateOptions((boolean) w, "settings_app_filter");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
findPreference("settings_app_filter_list").setOnPreferenceClickListener(preference -> {
|
||||||
|
startActivity(new Intent(getActivity(), FilterAppProxyActivity.class));
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
findPreference("settings_check_update").setOnPreferenceClickListener(preference -> {
|
findPreference("settings_check_update").setOnPreferenceClickListener(preference -> {
|
||||||
Daedalus.openUri("https://github.com/iTXTech/Daedalus/releases");
|
Daedalus.openUri("https://github.com/iTXTech/Daedalus/releases");
|
||||||
return false;
|
return false;
|
||||||
@ -110,11 +127,12 @@ public class GlobalConfigFragment extends PreferenceFragment {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
updateAdvancedOptions(advanced.isChecked());
|
updateOptions(advanced.isChecked(), "settings_advanced");
|
||||||
|
updateOptions(app_filter.isChecked(), "settings_app_filter");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAdvancedOptions(boolean checked) {
|
private void updateOptions(boolean checked, String pref) {
|
||||||
PreferenceCategory category = (PreferenceCategory) findPreference("settings_advanced");
|
PreferenceCategory category = (PreferenceCategory) findPreference(pref);
|
||||||
for (int i = 1; i < category.getPreferenceCount(); i++) {
|
for (int i = 1; i < category.getPreferenceCount(); i++) {
|
||||||
Preference preference = category.getPreference(i);
|
Preference preference = category.getPreference(i);
|
||||||
if (checked) {
|
if (checked) {
|
||||||
|
@ -7,12 +7,15 @@ import android.app.NotificationManager;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.net.VpnService;
|
import android.net.VpnService;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
import org.itxtech.daedalus.Daedalus;
|
import org.itxtech.daedalus.Daedalus;
|
||||||
import org.itxtech.daedalus.R;
|
import org.itxtech.daedalus.R;
|
||||||
import org.itxtech.daedalus.activity.MainActivity;
|
import org.itxtech.daedalus.activity.MainActivity;
|
||||||
@ -28,6 +31,7 @@ import java.net.Inet6Address;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Daedalus Project
|
* Daedalus Project
|
||||||
@ -238,7 +242,28 @@ public class DaedalusVpnService extends VpnService implements Runnable {
|
|||||||
.setConfigureIntent(PendingIntent.getActivity(this, 0,
|
.setConfigureIntent(PendingIntent.getActivity(this, 0,
|
||||||
new Intent(this, MainActivity.class).putExtra(MainActivity.LAUNCH_FRAGMENT, MainActivity.FRAGMENT_SETTINGS),
|
new Intent(this, MainActivity.class).putExtra(MainActivity.LAUNCH_FRAGMENT, MainActivity.FRAGMENT_SETTINGS),
|
||||||
PendingIntent.FLAG_ONE_SHOT));
|
PendingIntent.FLAG_ONE_SHOT));
|
||||||
|
|
||||||
|
//Set App Filter
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && Daedalus.getPrefs().getBoolean("settings_app_filter_switch", false)) {
|
||||||
|
Set<String> apps = Daedalus.getPrefs().getStringSet("filterAppObjects", null);
|
||||||
|
if (apps != null) {
|
||||||
|
boolean mode = Daedalus.getPrefs().getBoolean("settings_app_filter_mode_switch", false);
|
||||||
|
for (String app : apps) {
|
||||||
|
try {
|
||||||
|
if (mode) {
|
||||||
|
builder.addDisallowedApplication(app);
|
||||||
|
} else {
|
||||||
|
builder.addAllowedApplication(app);
|
||||||
|
}
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
Logger.error("Package Not Found:" + app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String format = null;
|
String format = null;
|
||||||
|
|
||||||
for (String prefix : new String[]{"10.0.0", "192.0.2", "198.51.100", "203.0.113", "192.168.50"}) {
|
for (String prefix : new String[]{"10.0.0", "192.0.2", "198.51.100", "203.0.113", "192.168.50"}) {
|
||||||
try {
|
try {
|
||||||
builder.addAddress(prefix + ".1", 24);
|
builder.addAddress(prefix + ".1", 24);
|
||||||
@ -303,8 +328,10 @@ public class DaedalusVpnService extends VpnService implements Runnable {
|
|||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException ignored) {
|
} catch (
|
||||||
} catch (Exception e) {
|
InterruptedException ignored) {
|
||||||
|
} catch (
|
||||||
|
Exception e) {
|
||||||
Logger.logException(e);
|
Logger.logException(e);
|
||||||
} finally {
|
} finally {
|
||||||
Log.d(TAG, "quit");
|
Log.d(TAG, "quit");
|
||||||
|
@ -2,6 +2,7 @@ package org.itxtech.daedalus.util;
|
|||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
|
|
||||||
import org.itxtech.daedalus.Daedalus;
|
import org.itxtech.daedalus.Daedalus;
|
||||||
import org.itxtech.daedalus.util.server.CustomDNSServer;
|
import org.itxtech.daedalus.util.server.CustomDNSServer;
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ public class Configurations {
|
|||||||
private static File file;
|
private static File file;
|
||||||
|
|
||||||
private ArrayList<CustomDNSServer> customDNSServers;
|
private ArrayList<CustomDNSServer> customDNSServers;
|
||||||
|
private ArrayList<String> filterAppObjects;
|
||||||
|
|
||||||
private ArrayList<Rule> hostsRules;
|
private ArrayList<Rule> hostsRules;
|
||||||
private ArrayList<Rule> dnsmasqRules;
|
private ArrayList<Rule> dnsmasqRules;
|
||||||
@ -66,6 +68,13 @@ public class Configurations {
|
|||||||
return customDNSServers;
|
return customDNSServers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArrayList<String> getFilterAppObjects() {
|
||||||
|
if (filterAppObjects == null) {
|
||||||
|
filterAppObjects = new ArrayList<>();
|
||||||
|
}
|
||||||
|
return filterAppObjects;
|
||||||
|
}
|
||||||
|
|
||||||
public ArrayList<Rule> getHostsRules() {
|
public ArrayList<Rule> getHostsRules() {
|
||||||
if (hostsRules == null) {
|
if (hostsRules == null) {
|
||||||
hostsRules = new ArrayList<>();
|
hostsRules = new ArrayList<>();
|
||||||
|
31
app/src/main/res/layout/activity_filter_app.xml
Normal file
31
app/src/main/res/layout/activity_filter_app.xml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="@style/AppTheme.AppBarOverlay">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar_filter"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?android:attr/actionBarSize"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerView_app_filter_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
32
app/src/main/res/layout/card_appview.xml
Normal file
32
app/src/main/res/layout/card_appview.xml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/app_icon"
|
||||||
|
android:layout_width="46dp"
|
||||||
|
android:layout_height="46dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingLeft="14dp"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:paddingStart="14dp" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/app_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.0" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatCheckBox
|
||||||
|
android:id="@+id/app_check"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="false"
|
||||||
|
android:paddingEnd="6dp"
|
||||||
|
android:paddingLeft="2dp"
|
||||||
|
android:paddingRight="6dp"
|
||||||
|
android:paddingStart="2dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -83,6 +83,12 @@
|
|||||||
<string name="settings_server_address">服务器地址</string>
|
<string name="settings_server_address">服务器地址</string>
|
||||||
<string name="settings_server_port">服务器端口</string>
|
<string name="settings_server_port">服务器端口</string>
|
||||||
|
|
||||||
|
<string name="settings_app_filter">分应用代理</string>
|
||||||
|
<string name="settings_app_filter_list">选择应用</string>
|
||||||
|
<string name="settings_app_filter_mode">黑名单模式</string>
|
||||||
|
<string name="settings_app_filter_list_summary">选择要过滤的应用</string>
|
||||||
|
<string name="settings_app_filter_summary">仅支持Android Lollipop及以上版本</string>
|
||||||
|
|
||||||
<string name="server_pdomo_primary">PdoMo DNS 主服务器</string>
|
<string name="server_pdomo_primary">PdoMo DNS 主服务器</string>
|
||||||
<string name="server_pdomo_secondary">PdoMo DNS 辅服务器</string>
|
<string name="server_pdomo_secondary">PdoMo DNS 辅服务器</string>
|
||||||
<string name="server_puredns_south_china">PureDNS 华南</string>
|
<string name="server_puredns_south_china">PureDNS 华南</string>
|
||||||
|
@ -83,6 +83,12 @@
|
|||||||
<string name="settings_server_address">伺服器網址</string>
|
<string name="settings_server_address">伺服器網址</string>
|
||||||
<string name="settings_server_port">伺服器埠</string>
|
<string name="settings_server_port">伺服器埠</string>
|
||||||
|
|
||||||
|
<string name="settings_app_filter">分應用代理</string>
|
||||||
|
<string name="settings_app_filter_list">選擇應用</string>
|
||||||
|
<string name="settings_app_filter_mode">黑名單模式</string>
|
||||||
|
<string name="settings_app_filter_list_summary">選擇要過濾的應用</string>
|
||||||
|
<string name="settings_app_filter_summary">僅支持Android Lollipop及以上版本</string>
|
||||||
|
|
||||||
<string name="server_pdomo_primary">PdoMo DNS 主伺服器</string>
|
<string name="server_pdomo_primary">PdoMo DNS 主伺服器</string>
|
||||||
<string name="server_pdomo_secondary">PdoMo DNS 輔伺服器</string>
|
<string name="server_pdomo_secondary">PdoMo DNS 輔伺服器</string>
|
||||||
<string name="server_puredns_south_china">PureDNS 華南</string>
|
<string name="server_puredns_south_china">PureDNS 華南</string>
|
||||||
|
@ -88,6 +88,12 @@
|
|||||||
<string name="settings_server_address">Server Address</string>
|
<string name="settings_server_address">Server Address</string>
|
||||||
<string name="settings_server_port">Server Port</string>
|
<string name="settings_server_port">Server Port</string>
|
||||||
|
|
||||||
|
<string name="settings_app_filter">App Filter</string>
|
||||||
|
<string name="settings_app_filter_mode">Blacklist mode</string>
|
||||||
|
<string name="settings_app_filter_list">Select application</string>
|
||||||
|
<string name="settings_app_filter_list_summary">Select an app to filter</string>
|
||||||
|
<string name="settings_app_filter_summary">Only supports Android Lollipop and above</string>
|
||||||
|
|
||||||
<string name="server_pdomo_primary">PdoMo DNS Primary</string>
|
<string name="server_pdomo_primary">PdoMo DNS Primary</string>
|
||||||
<string name="server_pdomo_secondary">PdoMo DNS Secondary</string>
|
<string name="server_pdomo_secondary">PdoMo DNS Secondary</string>
|
||||||
<string name="server_puredns_south_china">PureDNS South China</string>
|
<string name="server_puredns_south_china">PureDNS South China</string>
|
||||||
|
@ -48,6 +48,26 @@
|
|||||||
android:title="@string/settings_log_size"/>
|
android:title="@string/settings_log_size"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="settings_app_filter"
|
||||||
|
android:title="@string/settings_app_filter">
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="settings_app_filter_switch"
|
||||||
|
android:title="@string/settings_app_filter"
|
||||||
|
android:summary="@string/settings_app_filter_summary"
|
||||||
|
android:defaultValue="false"/>
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="settings_app_filter_mode_switch"
|
||||||
|
android:title="@string/settings_app_filter_mode"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:enabled="false"/>
|
||||||
|
<org.itxtech.daedalus.widget.ClickPreference
|
||||||
|
android:key="settings_app_filter_list"
|
||||||
|
android:title="@string/settings_app_filter_list"
|
||||||
|
android:summary="@string/settings_app_filter_list_summary"
|
||||||
|
android:enabled="false"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="settings_advanced"
|
android:key="settings_advanced"
|
||||||
android:title="@string/settings_advanced">
|
android:title="@string/settings_advanced">
|
||||||
|
Loading…
Reference in New Issue
Block a user