Added Disconnect category selection

pull/212/head
M66B 2 years ago
parent 06e840747a
commit 547c5c2e77

@ -45,9 +45,11 @@ import javax.net.ssl.HttpsURLConnection;
public class DisconnectBlacklist { public class DisconnectBlacklist {
private static final Map<String, List<String>> map = new HashMap<>(); private static final Map<String, List<String>> map = new HashMap<>();
private static final List<String> all = new ArrayList<>();
private final static int FETCH_TIMEOUT = 20 * 1000; // milliseconds private final static int FETCH_TIMEOUT = 20 * 1000; // milliseconds
private final static String LIST = "https://raw.githubusercontent.com/disconnectme/disconnect-tracking-protection/master/services.json"; private final static String LIST = "https://raw.githubusercontent.com/disconnectme/disconnect-tracking-protection/master/services.json";
final static String URI_CATEGORIES = "https://disconnect.me/trackerprotection#categories-of-trackers";
static void init(Context context) { static void init(Context context) {
final File file = getFile(context); final File file = getFile(context);
@ -70,6 +72,7 @@ public class DisconnectBlacklist {
long start = SystemClock.elapsedRealtime(); long start = SystemClock.elapsedRealtime();
map.clear(); map.clear();
all.clear();
String json = Helper.readText(file); String json = Helper.readText(file);
JSONObject jdisconnect = new JSONObject(json); JSONObject jdisconnect = new JSONObject(json);
@ -77,6 +80,7 @@ public class DisconnectBlacklist {
Iterator<String> categories = jcategories.keys(); Iterator<String> categories = jcategories.keys();
while (categories.hasNext()) { while (categories.hasNext()) {
String category = categories.next(); String category = categories.next();
all.add(category);
JSONArray jcategory = jcategories.getJSONArray(category); JSONArray jcategory = jcategories.getJSONArray(category);
for (int c = 0; c < jcategory.length(); c++) { for (int c = 0; c < jcategory.length(); c++) {
JSONObject jblock = (JSONObject) jcategory.get(c); JSONObject jblock = (JSONObject) jcategory.get(c);
@ -135,15 +139,34 @@ public class DisconnectBlacklist {
init(file); init(file);
} }
static List<String> getCategories() {
synchronized (all) {
return new ArrayList<>(all);
}
}
static boolean isEnabled(Context context, String category) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("disconnect_" + category, !"Content".equals(category));
}
static void setEnabled(Context context, String category, boolean value) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putBoolean("disconnect_" + category, value).apply();
}
static List<String> getCategories(String domain) { static List<String> getCategories(String domain) {
return _getCategories(domain); return _getCategories(domain);
} }
static boolean isTracking(String host) { static boolean isTrackingImage(Context context, String host) {
List<String> categories = _getCategories(host); List<String> categories = _getCategories(host);
if (categories == null || categories.size() == 0) if (categories == null || categories.size() == 0)
return false; return false;
return !categories.contains("Content"); for (String category : categories)
if (isEnabled(context, category))
return true;
return false;
} }
private static List<String> _getCategories(String domain) { private static List<String> _getCategories(String domain) {

@ -36,6 +36,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.Spinner; import android.widget.Spinner;
@ -47,11 +48,14 @@ import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat; import androidx.appcompat.widget.SwitchCompat;
import androidx.constraintlayout.widget.Group; import androidx.constraintlayout.widget.Group;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.webkit.WebViewFeature; import androidx.webkit.WebViewFeature;
import java.io.IOException; import java.io.IOException;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale; import java.util.Locale;
public class FragmentOptionsPrivacy extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener { public class FragmentOptionsPrivacy extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener {
@ -92,6 +96,9 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
private SwitchCompat swDisconnectAutoUpdate; private SwitchCompat swDisconnectAutoUpdate;
private SwitchCompat swDisconnectLinks; private SwitchCompat swDisconnectLinks;
private SwitchCompat swDisconnectImages; private SwitchCompat swDisconnectImages;
private RecyclerView rvDisconnect;
private ImageButton ibDisconnectCategories;
private AdapterDisconnect adapter;
private SwitchCompat swMnemonic; private SwitchCompat swMnemonic;
private Button btnClearAll; private Button btnClearAll;
private TextView tvMnemonic; private TextView tvMnemonic;
@ -158,6 +165,8 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
swDisconnectAutoUpdate = view.findViewById(R.id.swDisconnectAutoUpdate); swDisconnectAutoUpdate = view.findViewById(R.id.swDisconnectAutoUpdate);
swDisconnectLinks = view.findViewById(R.id.swDisconnectLinks); swDisconnectLinks = view.findViewById(R.id.swDisconnectLinks);
swDisconnectImages = view.findViewById(R.id.swDisconnectImages); swDisconnectImages = view.findViewById(R.id.swDisconnectImages);
rvDisconnect = view.findViewById(R.id.rvDisconnect);
ibDisconnectCategories = view.findViewById(R.id.ibDisconnectCategories);
swMnemonic = view.findViewById(R.id.swMnemonic); swMnemonic = view.findViewById(R.id.swMnemonic);
btnClearAll = view.findViewById(R.id.btnClearAll); btnClearAll = view.findViewById(R.id.btnClearAll);
tvMnemonic = view.findViewById(R.id.tvMnemonic); tvMnemonic = view.findViewById(R.id.tvMnemonic);
@ -484,6 +493,19 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
@Override @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("disconnect_images", checked).apply(); prefs.edit().putBoolean("disconnect_images", checked).apply();
rvDisconnect.setAlpha(checked ? 1.0f : Helper.LOW_LIGHT);
}
});
rvDisconnect.setHasFixedSize(false);
rvDisconnect.setLayoutManager(new LinearLayoutManager(getContext()));
adapter = new AdapterDisconnect(getContext(), DisconnectBlacklist.getCategories());
rvDisconnect.setAdapter(adapter);
ibDisconnectCategories.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.view(v.getContext(), Uri.parse(DisconnectBlacklist.URI_CATEGORIES), true);
} }
}); });
@ -626,6 +648,7 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
swDisconnectAutoUpdate.setChecked(prefs.getBoolean("disconnect_auto_update", false)); swDisconnectAutoUpdate.setChecked(prefs.getBoolean("disconnect_auto_update", false));
swDisconnectLinks.setChecked(prefs.getBoolean("disconnect_links", true)); swDisconnectLinks.setChecked(prefs.getBoolean("disconnect_links", true));
swDisconnectImages.setChecked(prefs.getBoolean("disconnect_images", false)); swDisconnectImages.setChecked(prefs.getBoolean("disconnect_images", false));
rvDisconnect.setAlpha(swDisconnectImages.isChecked() ? 1.0f : Helper.LOW_LIGHT);
String mnemonic = prefs.getString("wipe_mnemonic", null); String mnemonic = prefs.getString("wipe_mnemonic", null);
swMnemonic.setChecked(mnemonic != null); swMnemonic.setChecked(mnemonic != null);
@ -634,4 +657,70 @@ public class FragmentOptionsPrivacy extends FragmentBase implements SharedPrefer
Log.e(ex); Log.e(ex);
} }
} }
public static class AdapterDisconnect extends RecyclerView.Adapter<AdapterDisconnect.ViewHolder> {
private Context context;
private LayoutInflater inflater;
private List<String> items;
public class ViewHolder extends RecyclerView.ViewHolder implements CompoundButton.OnCheckedChangeListener {
private CheckBox cbEnabled;
ViewHolder(View itemView) {
super(itemView);
cbEnabled = itemView.findViewById(R.id.cbEnabled);
}
private void wire() {
cbEnabled.setOnCheckedChangeListener(this);
}
private void unwire() {
cbEnabled.setOnCheckedChangeListener(null);
}
private void bindTo(String category) {
cbEnabled.setText(category);
cbEnabled.setChecked(DisconnectBlacklist.isEnabled(context, category));
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int pos = getAdapterPosition();
if (pos == RecyclerView.NO_POSITION)
return;
String category = items.get(pos);
DisconnectBlacklist.setEnabled(context, category, isChecked);
}
}
AdapterDisconnect(Context context, List<String> items) {
this.context = context;
this.inflater = LayoutInflater.from(context);
setHasStableIds(false);
this.items = items;
}
@Override
public int getItemCount() {
return items.size();
}
@Override
@NonNull
public AdapterDisconnect.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new AdapterDisconnect.ViewHolder(inflater.inflate(R.layout.item_disconnect_enabled, parent, false));
}
@Override
public void onBindViewHolder(@NonNull AdapterDisconnect.ViewHolder holder, int position) {
holder.unwire();
String category = items.get(position);
holder.bindTo(category);
holder.wire();
}
}
} }

@ -57,7 +57,6 @@ import android.text.style.TypefaceSpan;
import android.text.style.URLSpan; import android.text.style.URLSpan;
import android.text.style.UnderlineSpan; import android.text.style.UnderlineSpan;
import android.util.Base64; import android.util.Base64;
import android.util.Pair;
import android.util.Patterns; import android.util.Patterns;
import android.view.View; import android.view.View;
@ -2287,7 +2286,7 @@ public class HtmlHelper {
Uri uri = Uri.parse(img.attr("src")); Uri uri = Uri.parse(img.attr("src"));
String host = uri.getHost(); String host = uri.getHost();
if (host != null && !hosts.contains(host) && if (host != null && !hosts.contains(host) &&
!isTrackingHost(host, disconnect_images)) !isTrackingHost(context, host, disconnect_images))
hosts.add(host); hosts.add(host);
} }
} }
@ -2305,7 +2304,7 @@ public class HtmlHelper {
if (host == null || hosts.contains(host)) if (host == null || hosts.contains(host))
continue; continue;
if (isTrackingPixel(img) || isTrackingHost(host, disconnect_images)) { if (isTrackingPixel(img) || isTrackingHost(context, host, disconnect_images)) {
img.attr("src", sb.toString()); img.attr("src", sb.toString());
img.attr("alt", context.getString(R.string.title_legend_tracking_pixel)); img.attr("alt", context.getString(R.string.title_legend_tracking_pixel));
img.attr("height", "24"); img.attr("height", "24");
@ -2340,10 +2339,10 @@ public class HtmlHelper {
} }
} }
private static boolean isTrackingHost(String host, boolean disconnect_images) { private static boolean isTrackingHost(Context context, String host, boolean disconnect_images) {
if (TRACKING_HOSTS.contains(host)) if (TRACKING_HOSTS.contains(host))
return true; return true;
if (disconnect_images && DisconnectBlacklist.isTracking(host)) if (disconnect_images && DisconnectBlacklist.isTrackingImage(context, host))
return true; return true;
return false; return false;
} }

@ -691,6 +691,29 @@
app:layout_constraintTop_toBottomOf="@+id/swDisconnectLinks" app:layout_constraintTop_toBottomOf="@+id/swDisconnectLinks"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvDisconnect"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="12dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swDisconnectImages" />
<ImageButton
android:id="@+id/ibDisconnectCategories"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="12dp"
android:contentDescription="@string/title_info"
android:tooltipText="@string/title_info"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/rvDisconnect"
app:srcCompat="@drawable/twotone_info_24" />
<Button <Button
android:id="@+id/btnClearAll" android:id="@+id/btnClearAll"
style="?android:attr/buttonStyleSmall" style="?android:attr/buttonStyleSmall"
@ -701,7 +724,7 @@
android:drawablePadding="6dp" android:drawablePadding="6dp"
android:text="@string/title_advanced_clear_all" android:text="@string/title_advanced_clear_all"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swDisconnectImages" /> app:layout_constraintTop_toBottomOf="@id/ibDisconnectCategories" />
<TextView <TextView
android:id="@+id/tvClearAllHint" android:id="@+id/tvClearAllHint"

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/clItem"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/cbEnabled"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="blocklist"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
Loading…
Cancel
Save