Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions app/src/main/java/eu/faircode/netguard/ActivityMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -588,9 +588,7 @@ public void onRefresh() {
// Handle intent
checkExtras(getIntent());

// Warn about disabled blocking if ADB logging is on
if (!Util.isPlayStoreInstall() && prefs.getBoolean("log_logcat", false))
Toast.makeText(this, R.string.msg_log_logcat, Toast.LENGTH_SHORT).show();
updateResearchModeNotice();
}

@Override
Expand Down Expand Up @@ -657,6 +655,7 @@ protected void onResume() {
vpnEnabled && Util.isPrivateDnsBlocked(this) ? View.VISIBLE : View.GONE);
}
refreshPrivateDnsBypassBanner();
updateResearchModeNotice();

super.onResume();
}
Expand Down Expand Up @@ -687,9 +686,22 @@ public void onConfigurationChanged(Configuration newConfig) {
updateHorizontalPadding(findViewById(R.id.tvLocalNetwork), horizontalPadding);
updateHorizontalPadding(findViewById(R.id.tvPrivateDns), horizontalPadding);
updateHorizontalPadding(findViewById(R.id.tvPrivateDnsBypass), horizontalPadding);
updateResearchModeNotice();
updatePrivateDnsBypassBanner();
}

private void updateResearchModeNotice() {
TextView notice = findViewById(R.id.tvResearchMode);
if (notice == null)
return;
updateHorizontalPadding(notice, Math.max(
getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin),
Math.round(16 * getResources().getDisplayMetrics().density)));
notice.setVisibility(PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean("log_logcat", false) ? View.VISIBLE : View.GONE);
notice.setOnClickListener(view -> startActivity(new Intent(this, ActivitySettings.class)));
}

private void updatePrivateDnsBypassBanner() {
TextView tvPrivateDnsBypass = findViewById(R.id.tvPrivateDnsBypass);
if (tvPrivateDnsBypass == null)
Expand Down Expand Up @@ -1001,6 +1013,9 @@ public void onSharedPreferenceChanged(SharedPreferences prefs, String name) {

updatePrivateDnsBypassBanner();

} else if ("log_logcat".equals(name)) {
updateResearchModeNotice();

} else if ("block_dot".equals(name) || "log".equals(name)) {
refreshPrivateDnsBypassBanner();

Expand Down
19 changes: 19 additions & 0 deletions app/src/main/res/layout/main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,25 @@
app:titleTextColor="@android:color/white" />
</com.google.android.material.appbar.AppBarLayout>

<TextView
android:id="@+id/tvResearchMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"
android:focusable="true"
android:drawableStart="@drawable/ic_warning_amber"
android:drawablePadding="8dp"
android:drawableTint="?attr/colorError"
android:padding="8dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:text="@string/msg_research_mode_notice"
android:textAppearance="@style/TextSmall"
android:textColor="?attr/colorOff"
android:visibility="gone" />

<!--
Outside llApps on purpose: that container is hidden on the Timeline and
VPN tabs, and Timeline is where the app lands. A prompt to grant a
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@
<string name="msg_wg_identity_renewed">%1$s no longer knew this device, so TrackerControl registered a new one and updated the %1$s profiles on this device.</string>
<string name="msg_wg_provider_rejected">%1$s refused to set up this device: %2$s</string>
<string name="msg_wg_recovery_failed">WireGuard stopped responding. TrackerControl is trying to reconnect, and internet access may remain blocked until WireGuard recovers.</string>
<string name="summary_log_logcat">Research mode: identified trackers are logged to ADB and SNI extraction is enabled for better hostname detection. Retrieve logs with adb logcat using tag \'TC-Log\'.</string>
<string name="summary_log_logcat">Research mode disables tracker blocking. Identified trackers are logged to ADB and SNI extraction is enabled for better hostname detection. Retrieve logs with adb logcat using tag \'TC-Log\'.</string>
<string name="msg_research_mode_notice">Research mode is on. Tracker blocking is disabled. Tap to change settings.</string>

<string name="msg_sure">Are you sure?</string>
<string name="msg_started">Looking for trackers…</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package eu.faircode.netguard;

import static org.junit.Assert.*;
import static org.robolectric.Shadows.shadowOf;

import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.view.View;
import android.widget.TextView;
import androidx.preference.PreferenceManager;
import net.kollnig.missioncontrol.R;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.GraphicsMode;
import java.io.File;
import java.io.FileOutputStream;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = 35, qualifiers = "w320dp-h640dp")
@GraphicsMode(GraphicsMode.Mode.NATIVE)
public class ActivityMainResearchNoticeTest {
@Test
public void noticeFollowsResearchPreferenceOutsideTabContentAndOpensSettings() throws Exception {
ActivityMain activity = Robolectric.buildActivity(ActivityMain.class).get();
activity.setTheme(R.style.AppTheme_NoActionBar);
activity.getDelegate().installViewFactory();
activity.setContentView(R.layout.main);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
// SNI alone does not disable tracker blocking or mean Research is on.
prefs.edit().putBoolean("log_logcat", false).putBoolean("sni_enabled", true).commit();
activity.onSharedPreferenceChanged(prefs, "log_logcat");
TextView notice = activity.findViewById(R.id.tvResearchMode);
assertEquals(View.GONE, notice.getVisibility());

// Imported settings can enable Research without SNI. Still warn.
prefs.edit().putBoolean("log_logcat", true).putBoolean("sni_enabled", false).commit();
activity.onSharedPreferenceChanged(prefs, "log_logcat");
activity.findViewById(R.id.llApps).setVisibility(View.GONE);
assertEquals(View.VISIBLE, notice.getVisibility());
assertSame(activity.findViewById(R.id.tvPrivateDns).getParent(), notice.getParent());
assertTrue(notice.getText().toString().contains("Tracker blocking is disabled"));
notice.performClick();
assertEquals(ActivitySettings.class.getName(),
shadowOf(activity).getNextStartedActivity().getComponent().getClassName());

int width = Math.round(320 * activity.getResources().getDisplayMetrics().density);
View root = (View) notice.getParent();
root.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(width * 2, View.MeasureSpec.EXACTLY));
root.layout(0, 0, width, width * 2);
assertEquals(0, notice.getLayout().getEllipsisCount(notice.getLineCount() - 1));
Bitmap bitmap = Bitmap.createBitmap(width, notice.getHeight(), Bitmap.Config.ARGB_8888);
bitmap.eraseColor(android.graphics.Color.WHITE);
notice.draw(new Canvas(bitmap));
File output = new File("build/reports/research-mode-notice.png");
output.getParentFile().mkdirs();
try (FileOutputStream stream = new FileOutputStream(output)) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
}

prefs.edit().putBoolean("log_logcat", false).putBoolean("sni_enabled", true).commit();
activity.onSharedPreferenceChanged(prefs, "log_logcat");
assertEquals(View.GONE, notice.getVisibility());
}
}
Loading