From d930f20be6ccbed92c1681235ebcfbcbc859eb6f Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Wed, 17 May 2023 14:32:27 +0100 Subject: [PATCH 01/33] updated automated tests to use same calls as foreground tests --- .../common/service/RunTestService.java | 3 +- .../ooniprobe/common/service/ServiceUtil.java | 11 +++- .../domain/GenerateAutoRunServiceSuite.java | 50 +++------------ .../ooniprobe/test/TestAsyncTask.java | 15 ++++- .../GenerateAutoRunServiceSuiteTest.java | 63 +------------------ .../GenerateTestServiceSuiteAutoRun.java | 3 +- .../ooniprobe/test/TestAsyncTaskTest.java | 8 +-- 7 files changed, 41 insertions(+), 112 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/service/RunTestService.java b/app/src/main/java/org/openobservatory/ooniprobe/common/service/RunTestService.java index 221399f12..3f7c9a92e 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/common/service/RunTestService.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/common/service/RunTestService.java @@ -61,6 +61,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { if (testSuites == null || testSuites.size() == 0) return START_STICKY_COMPATIBILITY; boolean store_db = intent.getBooleanExtra("storeDB", true); + boolean unattended = intent.getBooleanExtra("unattended", false); Application app = ((Application) getApplication()); NotificationUtility.setChannel(getApplicationContext(), CHANNEL_ID, app.getString(R.string.Settings_AutomatedTesting_Label), false, false, false); Intent notificationIntent = new Intent(this, RunningActivity.class); @@ -78,7 +79,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { .setProgress(100, 0, false) .build(); - task = (TestAsyncTask) new TestAsyncTask(app, testSuites, store_db).execute(); + task = (TestAsyncTask) new TestAsyncTask(app, testSuites, store_db, unattended).execute(); //This intent is used to manage the stop test button in the notification Intent broadcastIntent = new Intent(); broadcastIntent.setAction(RunTestService.ACTION_INTERRUPT); diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java index 46d1a4de7..ce0ad60c2 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java @@ -79,20 +79,24 @@ public static void callCheckInAPI(Application app) { return; } - - AbstractSuite suite = d.generateAutoRunServiceSuite.generate(config); + AbstractSuite suite = d.generateAutoRunServiceSuite.generate(); ArrayList testSuites = new ArrayList<>(); testSuites.add(suite); testSuites.add(InstantMessagingSuite.initForAutoRun()); testSuites.add(CircumventionSuite.initForAutoRun()); testSuites.add(PerformanceSuite.initForAutoRun()); testSuites.add(ExperimentalSuite.initForAutoRun()); - ServiceUtil.startRunTestService(app, testSuites, false); + ServiceUtil.startRunTestService(app, testSuites, false, true); + d.generateAutoRunServiceSuite.markAsRan(); } public static void startRunTestService(Context context, ArrayList iTestSuites, boolean storeDB) { + startRunTestService(context, iTestSuites, storeDB,false); + } + + public static void startRunTestService(Context context, ArrayList iTestSuites, boolean storeDB, boolean unattended) { ArrayList testSuites = Lists.newArrayList( Iterables.filter(iTestSuites, testSuite -> !testSuite.isTestEmpty(d.preferenceManager)) ); @@ -100,6 +104,7 @@ public static void startRunTestService(Context context, ArrayList Intent serviceIntent = new Intent(context, RunTestService.class); serviceIntent.putExtra("testSuites", testSuites); serviceIntent.putExtra("storeDB", storeDB); + serviceIntent.putExtra("unattended", unattended); ContextCompat.startForegroundService(context, serviceIntent); } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/domain/GenerateAutoRunServiceSuite.java b/app/src/main/java/org/openobservatory/ooniprobe/domain/GenerateAutoRunServiceSuite.java index b7c4b2579..a511b847e 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/domain/GenerateAutoRunServiceSuite.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/domain/GenerateAutoRunServiceSuite.java @@ -31,47 +31,17 @@ public class GenerateAutoRunServiceSuite { this.app = application; } - public AbstractSuite generate( - OONICheckInConfig config - ) { - - try { - OONISession session = EngineProvider.get().newSession( - EngineProvider.get().getDefaultSessionConfig( - app, - String.join("-",BuildConfig.SOFTWARE_NAME, AbstractTest.UNATTENDED), - BuildConfig.VERSION_NAME, - new LoggerArray(), - pm.getProxyURL() - ) - ); - OONIContext ooniContext = session.newContextWithTimeout(30); - OONICheckInResults results = session.checkIn(ooniContext, config); - - if (results.getWebConnectivity() != null) { - List inputs = new ArrayList<>(); - for (OONIURLInfo url : results.getWebConnectivity().getUrls()) { - inputs.add(url.getUrl()); - } - - markAsRan(); - - return AbstractSuite.getSuite( - app, - "web_connectivity", - inputs, - AbstractTest.AUTORUN - ); - } - - return null; - } catch (Exception e) { - e.printStackTrace(); - ThirdPartyServices.logException(e); - return null; - } + public AbstractSuite generate() { + + return AbstractSuite.getSuite( + app, + "web_connectivity", + null, + AbstractTest.AUTORUN + ); } + public boolean shouldStart(Boolean isWifi, Boolean isCharging, Boolean isVPNInUse) { if (pm.testWifiOnly() && !isWifi) return false; @@ -86,7 +56,7 @@ public boolean shouldStart(Boolean isWifi, Boolean isCharging, Boolean isVPNInUs return true; } - private void markAsRan() { + public void markAsRan() { pm.updateAutorunDate(); pm.incrementAutorun(); } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/test/TestAsyncTask.java b/app/src/main/java/org/openobservatory/ooniprobe/test/TestAsyncTask.java index 5d3e685cd..f7e642221 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/test/TestAsyncTask.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/test/TestAsyncTask.java @@ -64,6 +64,7 @@ public class TestAsyncTask extends AsyncTask implements Abst private String proxy; private boolean store_db = true; + private boolean unattended; public static List getSuites() { return Arrays.asList(new WebsitesSuite(), new InstantMessagingSuite(), new CircumventionSuite(), new PerformanceSuite(), new ExperimentalSuite()); @@ -75,9 +76,10 @@ public TestAsyncTask(Application app, ArrayList testSuites) { this.proxy = app.getPreferenceManager().getProxyURL(); } - public TestAsyncTask(Application app, ArrayList testSuites, boolean store_db) { + public TestAsyncTask(Application app, ArrayList testSuites, boolean store_db, boolean unattended) { this(app, testSuites); this.store_db = store_db; + this.unattended = unattended; } private void registerConnChange() { @@ -159,8 +161,15 @@ private void runTest(AbstractTest... tests) { //This uses the wrapper private void downloadURLs() { try { - OONISession session = EngineProvider.get().newSession(EngineProvider.get().getDefaultSessionConfig( - app, BuildConfig.SOFTWARE_NAME, BuildConfig.VERSION_NAME, new LoggerArray(), proxy)); + OONISession session = EngineProvider.get().newSession( + EngineProvider.get().getDefaultSessionConfig( + app, + unattended ? String.join("-", BuildConfig.SOFTWARE_NAME, AbstractTest.UNATTENDED) : BuildConfig.SOFTWARE_NAME, + BuildConfig.VERSION_NAME, + new LoggerArray(), + proxy + ) + ); OONIContext ooniContext = session.newContextWithTimeout(30); OONICheckInConfig config = app.getOONICheckInConfig(); diff --git a/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateAutoRunServiceSuiteTest.java b/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateAutoRunServiceSuiteTest.java index f7c53c482..b220e7234 100644 --- a/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateAutoRunServiceSuiteTest.java +++ b/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateAutoRunServiceSuiteTest.java @@ -31,10 +31,7 @@ public class GenerateAutoRunServiceSuiteTest extends RobolectricAbstractTest { // Mocks - OONICheckInInfoWebConnectivity webConnectivityMock = mock(OONICheckInInfoWebConnectivity.class); PreferenceManager preferenceManagerMock = mock(PreferenceManager.class); - OONICheckInConfig ooniCheckConfigMock = mock(OONICheckInConfig.class); - OONICheckInResults ooniResultsMock = mock(OONICheckInResults.class); OONISession ooniSessionMock = mock(OONISession.class); // Engine && UseCase @@ -52,73 +49,19 @@ public void setUp() { } @Test - public void shouldNotStartTest() { + public void generateSuite() { // Act - AbstractSuite suite = generateSuite.generate(ooniCheckConfigMock); - - // Assert - Assert.assertNull(suite); - } - - @Test - public void generateSuite() throws Exception { - // Arrange - ArrayList suiteUrls = getTestUrls(); - - when(preferenceManagerMock.getEnabledCategoryArr()).thenReturn(new ArrayList() { - { - add("ALDR"); - add("REL"); - add("PORN"); - add("PROV"); - add("POLR"); - add("HUMR"); - add("ENV"); - } - }); - - when(webConnectivityMock.getUrls()).thenReturn(suiteUrls); - when(ooniResultsMock.getWebConnectivity()).thenReturn(webConnectivityMock); - when(ooniSessionMock.checkIn(any(), any())).thenReturn(ooniResultsMock); - - // Act - AbstractSuite suite = generateSuite.generate(ooniCheckConfigMock); + AbstractSuite suite = generateSuite.generate(); // Assert Assert.assertNotNull(suite); - verify(preferenceManagerMock, times(1)).updateAutorunDate(); - verify(preferenceManagerMock, times(1)).incrementAutorun(); Assert.assertEquals(1, suite.getTestList(preferenceManagerMock).length); AbstractTest webTest = suite.getTestList(preferenceManagerMock)[0]; Assert.assertEquals("web_connectivity", webTest.getName()); - Assert.assertEquals(suiteUrls.size(), webTest.getInputs().size()); - - for (int i = 0; i < webTest.getInputs().size(); i++) { - Assert.assertEquals( webTest.getInputs().get(i), suiteUrls.get(i).getUrl()); - } - } - - private ArrayList getTestUrls() { - Faker faker = new Faker(); - - OONIURLInfo url1 = mock(OONIURLInfo.class); - when(url1.getUrl()).thenReturn(faker.internet.url()); - - OONIURLInfo url2 = mock(OONIURLInfo.class); - when(url1.getUrl()).thenReturn(faker.internet.url()); - - OONIURLInfo url3 = mock(OONIURLInfo.class); - when(url1.getUrl()).thenReturn(faker.internet.url()); + Assert.assertNull(webTest.getInputs()); - return new ArrayList(){ - { - add(url1); - add(url2); - add(url3); - } - }; } } \ No newline at end of file diff --git a/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateTestServiceSuiteAutoRun.java b/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateTestServiceSuiteAutoRun.java index 705fe657e..d5b853908 100644 --- a/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateTestServiceSuiteAutoRun.java +++ b/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateTestServiceSuiteAutoRun.java @@ -1,3 +1,4 @@ +/* package org.openobservatory.ooniprobe.domain; import androidx.test.filters.SmallTest; @@ -117,4 +118,4 @@ private ArrayList getTestUrls() { }; } -} \ No newline at end of file +}*/ diff --git a/app/src/test/java/org/openobservatory/ooniprobe/test/TestAsyncTaskTest.java b/app/src/test/java/org/openobservatory/ooniprobe/test/TestAsyncTaskTest.java index 56816f49e..0e8c69813 100644 --- a/app/src/test/java/org/openobservatory/ooniprobe/test/TestAsyncTaskTest.java +++ b/app/src/test/java/org/openobservatory/ooniprobe/test/TestAsyncTaskTest.java @@ -161,7 +161,7 @@ public void runTest_withProgress() { AbstractTest test = mock(AbstractTest.class); when(mockedSuite.getTestList(any())).thenReturn(new AbstractTest[]{test}); - TestAsyncTask task = new TestAsyncTask(a, suiteList, false); + TestAsyncTask task = new TestAsyncTask(a, suiteList, false,false); // Act task.execute(); @@ -189,14 +189,14 @@ public void runTest_withError() { when(mockedSuite.getTestList(any())).thenReturn(new AbstractTest[]{test}); doThrow(new RuntimeException("")).when(test).run(any(), any(), any(), any(), any(), anyInt(), any()); - TestAsyncTask task = new TestAsyncTask(a, suiteList,false); + TestAsyncTask task = new TestAsyncTask(a, suiteList,false,false); // Act task.execute(); idleTaskUntilFinished(task); // Assert - verify(runService).stopSelf(); + verify(runService).stopSelf(); } @Test @@ -209,7 +209,7 @@ public void runTest_interrupt() { when(mockedSuite.getTestList(any())).thenReturn(new AbstractTest[]{test}); when(test.canInterrupt()).thenReturn(true); - TestAsyncTask task = new TestAsyncTask(a, suiteList, false); + TestAsyncTask task = new TestAsyncTask(a, suiteList, false,false); // Act task.execute(); From 64e3e6a055f8baa2d694295983b9ba3b612627fa Mon Sep 17 00:00:00 2001 From: Norbel AMBANUMBEN Date: Fri, 16 Jun 2023 10:33:11 +0100 Subject: [PATCH 02/33] Update app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java Co-authored-by: Simone Basso --- .../openobservatory/ooniprobe/common/service/ServiceUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java index ce0ad60c2..48fa8822f 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java @@ -93,7 +93,7 @@ public static void callCheckInAPI(Application app) { public static void startRunTestService(Context context, ArrayList iTestSuites, boolean storeDB) { - startRunTestService(context, iTestSuites, storeDB,false); + startRunTestService(context, iTestSuites, storeDB, false); } public static void startRunTestService(Context context, ArrayList iTestSuites, boolean storeDB, boolean unattended) { From 080dcc2e7c32fbd616e9c36f3a0e0d1f14955f02 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Fri, 16 Jun 2023 10:57:18 +0100 Subject: [PATCH 03/33] updated code based on review --- .../ooniprobe/activity/RunningActivity.java | 2 +- .../ooniprobe/common/service/RunTestJobService.java | 2 +- .../ooniprobe/common/service/ServiceUtil.java | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/RunningActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/RunningActivity.java index 31f42857d..0bf7fd7b2 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/RunningActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/RunningActivity.java @@ -124,7 +124,7 @@ public static void runAsForegroundService(AbstractActivity context, private static void startRunTestService(AbstractActivity context, ArrayList testSuites, OnTestServiceStartedListener onTestServiceStartedListener) { - ServiceUtil.startRunTestService(context, testSuites, true); + ServiceUtil.startRunTestServiceManual(context, testSuites, true); onTestServiceStartedListener.onTestServiceStarted(); } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/service/RunTestJobService.java b/app/src/main/java/org/openobservatory/ooniprobe/common/service/RunTestJobService.java index 2df95f322..37fe91292 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/common/service/RunTestJobService.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/common/service/RunTestJobService.java @@ -34,7 +34,7 @@ public JobTask(JobService jobService, Application app) { @Override protected JobParameters doInBackground(JobParameters... params) { - ServiceUtil.callCheckInAPI(app); + ServiceUtil.startRunTestServiceUnattended(app); return params[0]; } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java index ce0ad60c2..9d954c880 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java @@ -68,7 +68,7 @@ public static void stopJob(Context context) { } } - public static void callCheckInAPI(Application app) { + public static void startRunTestServiceUnattended(Application app) { app.getServiceComponent().inject(d); boolean isVPNInUse = ReachabilityManager.isVPNinUse(app); @@ -86,17 +86,17 @@ public static void callCheckInAPI(Application app) { testSuites.add(CircumventionSuite.initForAutoRun()); testSuites.add(PerformanceSuite.initForAutoRun()); testSuites.add(ExperimentalSuite.initForAutoRun()); - ServiceUtil.startRunTestService(app, testSuites, false, true); + ServiceUtil.startRunTestServiceCommon(app, testSuites, false, true); d.generateAutoRunServiceSuite.markAsRan(); } - public static void startRunTestService(Context context, ArrayList iTestSuites, boolean storeDB) { - startRunTestService(context, iTestSuites, storeDB,false); + public static void startRunTestServiceManual(Context context, ArrayList iTestSuites, boolean storeDB) { + startRunTestServiceCommon(context, iTestSuites, storeDB,false); } - public static void startRunTestService(Context context, ArrayList iTestSuites, boolean storeDB, boolean unattended) { + private static void startRunTestServiceCommon(Context context, ArrayList iTestSuites, boolean storeDB, boolean unattended) { ArrayList testSuites = Lists.newArrayList( Iterables.filter(iTestSuites, testSuite -> !testSuite.isTestEmpty(d.preferenceManager)) ); From 9d1f1c62fdeab6248ab04aca2e92f5ec61a56d1a Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Thu, 29 Jun 2023 19:35:55 +0100 Subject: [PATCH 04/33] Deleted `GenerateTestServiceSuiteAutoRun` since its a duplicate of `GenerateAutoRunServiceSuiteTest` --- .../GenerateTestServiceSuiteAutoRun.java | 121 ------------------ 1 file changed, 121 deletions(-) delete mode 100644 app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateTestServiceSuiteAutoRun.java diff --git a/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateTestServiceSuiteAutoRun.java b/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateTestServiceSuiteAutoRun.java deleted file mode 100644 index d5b853908..000000000 --- a/app/src/test/java/org/openobservatory/ooniprobe/domain/GenerateTestServiceSuiteAutoRun.java +++ /dev/null @@ -1,121 +0,0 @@ -/* -package org.openobservatory.ooniprobe.domain; - -import androidx.test.filters.SmallTest; - -import org.junit.Assert; -import org.junit.Test; -import org.openobservatory.engine.OONICheckInConfig; -import org.openobservatory.engine.OONICheckInResults; -import org.openobservatory.engine.OONICheckInResults.OONICheckInInfoWebConnectivity; -import org.openobservatory.engine.OONISession; -import org.openobservatory.engine.OONIURLInfo; -import org.openobservatory.ooniprobe.RobolectricAbstractTest; -import org.openobservatory.ooniprobe.common.PreferenceManager; -import org.openobservatory.ooniprobe.engine.TestEngineInterface; -import org.openobservatory.ooniprobe.test.EngineInterface; -import org.openobservatory.ooniprobe.test.EngineProvider; -import org.openobservatory.ooniprobe.test.suite.AbstractSuite; -import org.openobservatory.ooniprobe.test.test.AbstractTest; - -import java.util.ArrayList; - -import io.bloco.faker.Faker; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@SmallTest -public class GenerateTestServiceSuiteAutoRun extends RobolectricAbstractTest { - - // Mocks - OONICheckInInfoWebConnectivity webConnectivityMock = mock(OONICheckInInfoWebConnectivity.class); - PreferenceManager preferenceManagerMock = mock(PreferenceManager.class); - OONICheckInConfig ooniCheckConfigMock = mock(OONICheckInConfig.class); - OONICheckInResults ooniResultsMock = mock(OONICheckInResults.class); - OONISession ooniSessionMock = mock(OONISession.class); - - // Engine && UseCase - EngineInterface mockedEngine = new TestEngineInterface(ooniSessionMock); - GenerateAutoRunServiceSuite generateSuite; - - @Override - public void setUp() { - super.setUp(); - generateSuite = new GenerateAutoRunServiceSuite(a, preferenceManagerMock); - EngineProvider.engineInterface = mockedEngine; - - when(preferenceManagerMock.testWifiOnly()).thenReturn(true); - when(preferenceManagerMock.testChargingOnly()).thenReturn(true); - } - - @Test - public void shouldNotStartTest() { - // Act - AbstractSuite suite = generateSuite.generate(ooniCheckConfigMock); - - // Assert - Assert.assertNull(suite); - } - - @Test - public void generateSuite() throws Exception { - // Arrange - ArrayList suiteUrls = getTestUrls(); - - when(preferenceManagerMock.getEnabledCategoryArr()).thenReturn(new ArrayList() { - { - add("ALDR"); - add("REL"); - add("PORN"); - add("PROV"); - add("POLR"); - add("HUMR"); - add("ENV"); - } - }); - - when(webConnectivityMock.getUrls()).thenReturn(suiteUrls); - when(ooniResultsMock.getWebConnectivity()).thenReturn(webConnectivityMock); - when(ooniSessionMock.checkIn(any(), any())).thenReturn(ooniResultsMock); - - // Act - AbstractSuite suite = generateSuite.generate(ooniCheckConfigMock); - - // Assert - Assert.assertNotNull(suite); - Assert.assertEquals(1, suite.getTestList(preferenceManagerMock).length); - - AbstractTest webTest = suite.getTestList(preferenceManagerMock)[0]; - - Assert.assertEquals("web_connectivity", webTest.getName()); - Assert.assertEquals(suiteUrls.size(), webTest.getInputs().size()); - - for (int i = 0; i < webTest.getInputs().size(); i++) { - Assert.assertEquals(webTest.getInputs().get(i), suiteUrls.get(i).getUrl()); - } - } - - private ArrayList getTestUrls() { - Faker faker = new Faker(); - - OONIURLInfo url1 = mock(OONIURLInfo.class); - when(url1.getUrl()).thenReturn(faker.internet.url()); - - OONIURLInfo url2 = mock(OONIURLInfo.class); - when(url1.getUrl()).thenReturn(faker.internet.url()); - - OONIURLInfo url3 = mock(OONIURLInfo.class); - when(url1.getUrl()).thenReturn(faker.internet.url()); - - return new ArrayList() { - { - add(url1); - add(url2); - add(url3); - } - }; - } - -}*/ From 0aef23c033842d4a8a23c432c938473c6e20c6f0 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Tue, 11 Jul 2023 01:38:15 +0100 Subject: [PATCH 05/33] updates gradle and android core dependencies --- app/build.gradle | 24 ++++++++++++------------ app/jacoco.gradle | 20 +++++++++++++------- build.gradle | 6 +++--- gradle.properties | 9 ++++++++- gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b57fbb3c6..bc9a38a72 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -104,11 +104,11 @@ dependencies { implementation project(path: ':engine') // AndroidX - implementation 'androidx.appcompat:appcompat:1.4.2' + implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.lifecycle:lifecycle-process:2.5.1' + implementation 'androidx.lifecycle:lifecycle-process:2.6.1' implementation 'androidx.preference:preference:1.2.0' - implementation 'com.google.android.material:material:1.6.1' + implementation 'com.google.android.material:material:1.9.0' implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' implementation 'com.google.guava:guava:30.1.1-android' implementation 'androidx.legacy:legacy-support-v4:1.0.0' @@ -151,9 +151,9 @@ dependencies { // Testing // Unit Testing testImplementation 'junit:junit:4.13.2' - testImplementation 'androidx.test:core:1.4.0' - testImplementation 'androidx.test:runner:1.4.0' - testImplementation 'androidx.test:rules:1.4.0' + testImplementation 'androidx.test:core:1.5.0' + testImplementation 'androidx.test:runner:1.5.2' + testImplementation 'androidx.test:rules:1.5.0' testImplementation 'org.mockito:mockito-core:4.6.1' testImplementation 'org.mockito:mockito-inline:4.6.1' testImplementation 'org.robolectric:robolectric:4.5.1' @@ -164,16 +164,16 @@ dependencies { // Instrumentation Testing androidTestImplementation 'tools.fastlane:screengrab:2.0.0' androidTestImplementation 'com.github.blocoio:faker:1.2.8' - androidTestImplementation 'androidx.test:runner:1.4.0' - androidTestImplementation 'androidx.test:rules:1.4.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0' - androidTestImplementation('androidx.test.espresso:espresso-contrib:3.4.0') { + androidTestImplementation 'androidx.test:runner:1.5.2' + androidTestImplementation 'androidx.test:rules:1.5.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1' + androidTestImplementation('androidx.test.espresso:espresso-contrib:3.5.1') { exclude group: 'com.android.support', module: 'appcompat' exclude group: 'com.android.support', module: 'support-v4' exclude module: 'recyclerview-v7' } - androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0') { + androidTestImplementation('androidx.test.espresso:espresso-core:3.5.1') { exclude group: 'com.android.support', module: 'appcompat' exclude group: 'com.android.support', module: 'support-v4' exclude module: 'recyclerview-v7' diff --git a/app/jacoco.gradle b/app/jacoco.gradle index 816940653..fc15cd854 100644 --- a/app/jacoco.gradle +++ b/app/jacoco.gradle @@ -48,13 +48,19 @@ task jacocoAndroidTestReport(type: JacocoReport) { executionData.from += fileTree(dir: codeCoverageDataLocation, includes: ['**/*.ec']) } - reports { - html.enabled true - html.destination file("${buildDir}/reports/coverage") - xml.enabled true - xml.destination file("${buildDir}/reports/coverage.xml") - csv.enabled false - } + reports { + html { + enabled true + destination file("${buildDir}/reports/coverage") + } + xml { + enabled true + destination file("${buildDir}/reports/coverage.xml") + } + csv { + enabled false + } + } doLast { println "Wrote HTML coverage report to ${reports.html.destination}/index.html" diff --git a/build.gradle b/build.gradle index 1fcb28081..4bc79ec72 100644 --- a/build.gradle +++ b/build.gradle @@ -6,9 +6,9 @@ buildscript { maven { url "https://jitpack.io" } } dependencies { - classpath 'com.android.tools.build:gradle:7.4.1' - classpath 'com.google.gms:google-services:4.3.13' - classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21' + classpath 'com.android.tools.build:gradle:8.0.2' + classpath 'com.google.gms:google-services:4.3.15' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0' } } diff --git a/gradle.properties b/gradle.properties index 8de505811..aefd6ef7e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,9 +6,16 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. +android.defaults.buildfeatures.buildconfig=true android.enableJetifier=true +android.nonFinalResIds=false +android.nonTransitiveRClass=false android.useAndroidX=true -org.gradle.jvmargs=-Xmx1536m +# https://github.com/JakeWharton/butterknife/issues/1686 +org.gradle.jvmargs=-Xmx1920M \ +--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ +--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ +--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2ec77e51a..3a0290794 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From d8d7130ce56ade1736d0a7b2779a26a991efec9a Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Tue, 11 Jul 2023 07:04:39 +0100 Subject: [PATCH 06/33] changed java version in build files --- .github/workflows/build.yml | 6 +++--- .github/workflows/emulator.yml | 6 +++--- .github/workflows/test.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6ed6c7a7e..240c10008 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,10 +10,10 @@ jobs: - "StableFullRelease" - "StableFdroidRelease" steps: - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '17' distribution: 'temurin' - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - run: ./gradlew build${{ matrix.version }} && ./gradlew clean diff --git a/.github/workflows/emulator.yml b/.github/workflows/emulator.yml index 0a599c15a..5cd77a8df 100644 --- a/.github/workflows/emulator.yml +++ b/.github/workflows/emulator.yml @@ -15,12 +15,12 @@ jobs: api-level: [29] target: [google_apis] steps: - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '17' distribution: 'temurin' - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: run tests uses: reactivecircus/android-emulator-runner@v2 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e678fedd6..35a1bfb9c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,12 +5,12 @@ jobs: test: runs-on: macos-latest steps: - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '17' distribution: 'temurin' - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - run: ./gradlew testStableFullRelease - name: uploads test results uses: actions/upload-artifact@v2 From 6b40161e9f0d43ade12e682d1ff323af271cd8d7 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sat, 15 Jul 2023 14:03:19 +0100 Subject: [PATCH 07/33] modified build files to sopport jdk 17 --- app/build.gradle | 2 +- app/jacoco.gradle | 2 +- gradle.properties | 14 +++++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index bc9a38a72..e00113ca2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -156,7 +156,7 @@ dependencies { testImplementation 'androidx.test:rules:1.5.0' testImplementation 'org.mockito:mockito-core:4.6.1' testImplementation 'org.mockito:mockito-inline:4.6.1' - testImplementation 'org.robolectric:robolectric:4.5.1' + testImplementation 'org.robolectric:robolectric:4.10.3' testImplementation 'com.github.blocoio:faker:1.2.8' testImplementation 'org.ooni:oonimkall:2023.06.08-161352' testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.36' diff --git a/app/jacoco.gradle b/app/jacoco.gradle index fc15cd854..add082a31 100644 --- a/app/jacoco.gradle +++ b/app/jacoco.gradle @@ -1,7 +1,7 @@ apply plugin: 'jacoco' jacoco { - toolVersion '0.8.5' + toolVersion '0.8.7' } task jacocoAndroidTestReport(type: JacocoReport) { diff --git a/gradle.properties b/gradle.properties index aefd6ef7e..eb2a51767 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,9 +13,17 @@ android.nonTransitiveRClass=false android.useAndroidX=true # https://github.com/JakeWharton/butterknife/issues/1686 org.gradle.jvmargs=-Xmx1920M \ ---add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ ---add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ ---add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED +--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ +--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED + # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects From 9cb5b81dbacf0594114b3545a34e6613b0526ac1 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sat, 15 Jul 2023 15:17:09 +0100 Subject: [PATCH 08/33] updates depricated gradle functions --- app/build.gradle | 6 +----- build.gradle | 2 +- engine/build.gradle | 9 ++++----- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e00113ca2..c6451c5ab 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -53,7 +53,7 @@ android { } } - flavorDimensions 'testing', 'license' + flavorDimensions = ['testing', 'license'] productFlavors { stable { dimension 'testing' @@ -90,10 +90,6 @@ android { setIgnore(true) } } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } buildFeatures { viewBinding = true } diff --git a/build.gradle b/build.gradle index 4bc79ec72..fadbb2582 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,6 @@ allprojects { } } -task clean(type: Delete) { +tasks.register('clean', Delete) { delete rootProject.buildDir } diff --git a/engine/build.gradle b/engine/build.gradle index e3f19dd39..d1181bd12 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -1,12 +1,11 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 30 - buildToolsVersion "30.0.3" + compileSdk 33 defaultConfig { - minSdkVersion 19 - targetSdkVersion 30 + minSdk 19 + targetSdk 33 } compileOptions { @@ -14,7 +13,7 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } - flavorDimensions 'testing' + flavorDimensions = ['testing'] productFlavors { stable { dimension 'testing' From 1fb0d0fad8de731d80ec324696337b9469f49119 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Fri, 28 Jul 2023 09:20:42 +0100 Subject: [PATCH 09/33] updated dependencies --- app/build.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a8a470652..43754650a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -123,7 +123,7 @@ dependencies { annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' implementation 'com.github.xanscale.LocalhostToolkit:app:19.05.01' - implementation 'com.airbnb.android:lottie:3.0.7' + implementation 'com.airbnb.android:lottie:6.0.0' implementation 'com.google.code.gson:gson:2.8.9' implementation 'ru.noties:markwon:2.0.1' implementation 'commons-io:commons-io:2.6' @@ -133,13 +133,13 @@ dependencies { // Flavor fullImplementation platform('com.google.firebase:firebase-bom:26.3.0') fullImplementation 'com.google.firebase:firebase-messaging' - fullImplementation 'ly.count.android:sdk:21.11.0' + fullImplementation 'ly.count.android:sdk:23.6.0' fullImplementation 'io.sentry:sentry-android:6.3.0' fullImplementation 'com.google.android.play:core:1.10.3' // Dependency Injection - implementation 'com.google.dagger:dagger:2.36' - annotationProcessor 'com.google.dagger:dagger-compiler:2.36' + implementation 'com.google.dagger:dagger:2.44.2' + annotationProcessor 'com.google.dagger:dagger-compiler:2.44.2' // Logger implementation project(':applogger') @@ -155,7 +155,7 @@ dependencies { testImplementation 'org.robolectric:robolectric:4.10.3' testImplementation 'com.github.blocoio:faker:1.2.8' testImplementation 'org.ooni:oonimkall:2023.07.18-162729' - testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.36' + testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.44.2' // Instrumentation Testing androidTestImplementation 'tools.fastlane:screengrab:2.0.0' @@ -175,7 +175,7 @@ dependencies { exclude module: 'recyclerview-v7' } androidTestImplementation('com.schibsted.spain:barista:3.9.0') - androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.36" + androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.44.2" } static def versionCodeDate() { From 7e0b657b907a1a6d46768870725ddc58e2d90daa Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Tue, 1 Aug 2023 11:46:20 +0100 Subject: [PATCH 10/33] Updates intents in preferences to target class and package for consistent behaviour across various application flavors. --- app/build.gradle | 3 +++ app/src/dev/res/values/untranslatable.xml | 6 ------ app/src/experimental/res/values/untranslatable.xml | 6 ------ app/src/fdroid/res/xml/preferences_global.xml | 12 +++++++++--- app/src/main/res/xml/preferences_global.xml | 12 +++++++++--- 5 files changed, 21 insertions(+), 18 deletions(-) delete mode 100644 app/src/dev/res/values/untranslatable.xml delete mode 100644 app/src/experimental/res/values/untranslatable.xml diff --git a/app/build.gradle b/app/build.gradle index ac15c07d7..b1b52ef1b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,6 +14,7 @@ android { testInstrumentationRunner "org.openobservatory.ooniprobe.TestAndroidJUnitRunner" buildConfigField 'String', 'OONI_API_BASE_URL', '"https://api.ooni.io/"' buildConfigField 'String', 'NOTIFICATION_SERVER', '"https://countly.ooni.io"' + resValue "string", "APP_ID", 'org.openobservatory.ooniprobe' resValue "string", "APP_NAME", "OONI Probe" buildConfigField 'String', 'SOFTWARE_NAME', 'BASE_SOFTWARE_NAME+IS_DEBUG' buildConfigField 'String', 'COUNTLY_KEY', '"146836f41172f9e3287cab6f2cc347de3f5ddf3b"' @@ -65,6 +66,7 @@ android { versionNameSuffix "-beta.1" versionCode versionCodeDate() buildConfigField 'String', 'BASE_SOFTWARE_NAME', '"ooniprobe-android-dev"' + resValue "string", "APP_ID", 'org.openobservatory.ooniprobe.dev' resValue "string", "APP_NAME", "OONI Dev" buildConfigField 'String', 'COUNTLY_KEY', '"e6c2cfe53e85951d50567467cef3f9fa2eab32c3"' } @@ -74,6 +76,7 @@ android { versionNameSuffix "-experimental.1" versionCode versionCodeDate() buildConfigField 'String', 'BASE_SOFTWARE_NAME', '"ooniprobe-android-experimental"' + resValue "string", "APP_ID", 'org.openobservatory.ooniprobe.experimental' resValue "string", "APP_NAME", "OONI Exp" buildConfigField 'String', 'COUNTLY_KEY', '"e6c2cfe53e85951d50567467cef3f9fa2eab32c3"' } diff --git a/app/src/dev/res/values/untranslatable.xml b/app/src/dev/res/values/untranslatable.xml deleted file mode 100644 index 0a7ae877f..000000000 --- a/app/src/dev/res/values/untranslatable.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - org.openobservatory.ooniprobe.dev.activity.InfoActivity - org.openobservatory.ooniprobe.dev.activity.ProxyActivity - org.openobservatory.ooniprobe.dev.activity.LogActivity - \ No newline at end of file diff --git a/app/src/experimental/res/values/untranslatable.xml b/app/src/experimental/res/values/untranslatable.xml deleted file mode 100644 index 75568c958..000000000 --- a/app/src/experimental/res/values/untranslatable.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - org.openobservatory.ooniprobe.experimental.activity.InfoActivity - org.openobservatory.ooniprobe.experimental.activity.ProxyActivity - org.openobservatory.ooniprobe.experimental.activity.LogActivity - \ No newline at end of file diff --git a/app/src/fdroid/res/xml/preferences_global.xml b/app/src/fdroid/res/xml/preferences_global.xml index 26eea0e6d..3cbcc5cbf 100644 --- a/app/src/fdroid/res/xml/preferences_global.xml +++ b/app/src/fdroid/res/xml/preferences_global.xml @@ -355,7 +355,9 @@ app:iconSpaceReserved="false" android:key="logs" android:title="@string/Settings_Advanced_RecentLogs"> - + - + - + diff --git a/app/src/main/res/xml/preferences_global.xml b/app/src/main/res/xml/preferences_global.xml index 8b93cd241..c973e7ed1 100644 --- a/app/src/main/res/xml/preferences_global.xml +++ b/app/src/main/res/xml/preferences_global.xml @@ -348,7 +348,9 @@ android:icon="@drawable/proxy" android:key="@string/ooni_backend_proxy" android:title="@string/Settings_Proxy_Label"> - + - + - + From f98d2e3cce629be05ea252b0ab67d0296d584e21 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Thu, 3 Aug 2023 10:17:32 +0100 Subject: [PATCH 11/33] Update to `ViewBinding` --- .../ooniprobe/activity/RunningActivity.java | 86 +++++++------------ 1 file changed, 31 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/RunningActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/RunningActivity.java index d40d95dcb..32c62ce35 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/RunningActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/RunningActivity.java @@ -12,20 +12,12 @@ import android.os.Bundle; import android.view.View; import android.view.animation.Animation; -import android.widget.Button; -import android.widget.ImageButton; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import com.airbnb.lottie.LottieAnimationView; - import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.Application; import org.openobservatory.ooniprobe.common.PreferenceManager; @@ -33,6 +25,7 @@ import org.openobservatory.ooniprobe.common.TestProgressRepository; import org.openobservatory.ooniprobe.common.service.RunTestService; import org.openobservatory.ooniprobe.common.service.ServiceUtil; +import org.openobservatory.ooniprobe.databinding.ActivityRunningBinding; import org.openobservatory.ooniprobe.receiver.TestRunBroadRequestReceiver; import org.openobservatory.ooniprobe.test.suite.AbstractSuite; import org.openobservatory.ooniprobe.test.suite.ExperimentalSuite; @@ -42,36 +35,19 @@ import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.app.fragment.ConfirmDialogFragment; import localhost.toolkit.app.fragment.MessageDialogFragment; /** - * Serves to display progress of {@code RunTestService} running in in the background on a screen. + * Serves to display progress of {@code RunTestService} running in the background on a screen. * * Also contains {@link #runAsForegroundService(AbstractActivity, ArrayList,OnTestServiceStartedListener) runAsForegroundService} * used to start {@code RunTestService} in the background. */ public class RunningActivity extends AbstractActivity implements ConfirmDialogFragment.OnConfirmedListener { - @BindView(R.id.running) - TextView running; - @BindView(R.id.name) - TextView name; - @BindView(R.id.log) - TextView log; - @BindView(R.id.eta) - TextView eta; - @BindView(R.id.progress) - ProgressBar progress; - @BindView(R.id.close) - ImageButton close; - @BindView(R.id.stop) - Button stop; - @BindView(R.id.animation) - LottieAnimationView animation; - @BindView(R.id.proxy_icon) - RelativeLayout proxy_icon; + + ActivityRunningBinding binding; + private TestRunBroadRequestReceiver receiver; @Inject @@ -136,29 +112,29 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActivityComponent().inject(this); setTheme(R.style.Theme_MaterialComponents_NoActionBar_App); - setContentView(R.layout.activity_running); - ButterKnife.bind(this); + binding = ActivityRunningBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); testProgressRepository.getProgress().observe(this, progressValue -> { if (progressValue!=null) { - progress.setProgress(progressValue); + binding.progress.setProgress(progressValue); } }); testProgressRepository.getEta().observe(this,etaValue -> { if (etaValue!=null) { - eta.setText(readableTimeRemaining(etaValue)); + binding.eta.setText(readableTimeRemaining(etaValue)); } }); if (preferenceManager.getProxyURL().isEmpty()) - proxy_icon.setVisibility(View.GONE); - close.setOnClickListener(new View.OnClickListener() { + binding.proxyIcon.setVisibility(View.GONE); + binding.close.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); - stop.setOnClickListener(new View.OnClickListener() { + binding.stop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new ConfirmDialogFragment.Builder() @@ -176,33 +152,33 @@ private void applyUIChanges(RunTestService service) { service.task.currentSuite == null || service.task.currentTest == null) { return; } - animation.setImageAssetsFolder("anim/"); - animation.setRepeatCount(Animation.INFINITE); - animation.playAnimation(); + binding.animation.setImageAssetsFolder("anim/"); + binding.animation.setRepeatCount(Animation.INFINITE); + binding.animation.playAnimation(); Integer progressLevel = testProgressRepository.getProgress().getValue(); if (progressLevel != null) { - progress.setProgress(progressLevel); + binding.progress.setProgress(progressLevel); } else { - progress.setIndeterminate(true); + binding.progress.setIndeterminate(true); } Double etaValue = testProgressRepository.getEta().getValue(); if (etaValue!=null){ - eta.setText(readableTimeRemaining(etaValue)); + binding.eta.setText(readableTimeRemaining(etaValue)); }else { - eta.setText(R.string.Dashboard_Running_CalculatingETA); + binding.eta.setText(R.string.Dashboard_Running_CalculatingETA); } if (service.task.currentSuite.getName().equals(ExperimentalSuite.NAME)) - name.setText(service.task.currentTest.getName()); + binding.name.setText(service.task.currentTest.getName()); else - name.setText(getString(service.task.currentTest.getLabelResId())); + binding.name.setText(getString(service.task.currentTest.getLabelResId())); getWindow().setBackgroundDrawableResource(service.task.currentSuite.getColor()); if (Build.VERSION.SDK_INT >= 21) { getWindow().setStatusBarColor(service.task.currentSuite.getColor()); } - animation.setAnimation(service.task.currentSuite.getAnim()); - progress.setMax(service.task.getMax(preferenceManager)); + binding.animation.setAnimation(service.task.currentSuite.getAnim()); + binding.progress.setMax(service.task.getMax(preferenceManager)); } @Override @@ -264,20 +240,20 @@ public void onStart(RunTestService service) { @Override public void onRun(String value) { - name.setText(value); + binding.name.setText(value); } @Override public void onProgress(int state, double timeLeft) { - progress.setIndeterminate(false); - progress.setProgress(state); + binding.progress.setIndeterminate(false); + binding.progress.setProgress(state); - eta.setText(readableTimeRemaining(timeLeft)); + binding.eta.setText(readableTimeRemaining(timeLeft)); } @Override public void onLog(String value) { - log.setText(value); + binding.log.setText(value); } @Override @@ -287,13 +263,13 @@ public void onError(String value) { @Override public void onUrl() { - progress.setIndeterminate(false); + binding.progress.setIndeterminate(false); } @Override public void onInterrupt() { - running.setText(getString(R.string.Dashboard_Running_Stopping_Title)); - log.setText(getString(R.string.Dashboard_Running_Stopping_Notice)); + binding.running.setText(getString(R.string.Dashboard_Running_Stopping_Title)); + binding.log.setText(getString(R.string.Dashboard_Running_Stopping_Notice)); } @Override From 36b1bef07e13a2bb52a42b0299edd09577ed3bb6 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Thu, 3 Aug 2023 11:59:58 +0100 Subject: [PATCH 12/33] Update `OoniRunActivity` to use `Viewbinding` --- .../ooniprobe/activity/OoniRunActivity.java | 70 ++++++++----------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/OoniRunActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/OoniRunActivity.java index 89b32b674..50613aecf 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/OoniRunActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/OoniRunActivity.java @@ -6,21 +6,17 @@ import android.util.Patterns; import android.view.View; import android.webkit.URLUtil; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; import android.widget.Toast; -import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import com.google.gson.Gson; import org.openobservatory.ooniprobe.BuildConfig; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.PreferenceManager; +import org.openobservatory.ooniprobe.databinding.ActivityOonirunBinding; import org.openobservatory.ooniprobe.domain.GetTestSuite; import org.openobservatory.ooniprobe.domain.VersionCompare; import org.openobservatory.ooniprobe.domain.models.Attribute; @@ -33,19 +29,11 @@ import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerAdapter; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; public class OoniRunActivity extends AbstractActivity { - @BindView(R.id.toolbar) Toolbar toolbar; - @BindView(R.id.icon) ImageView icon; - @BindView(R.id.iconBig) ImageView iconBig; - @BindView(R.id.title) TextView title; - @BindView(R.id.desc) TextView desc; - @BindView(R.id.run) Button run; - @BindView(R.id.recycler) RecyclerView recycler; + ActivityOonirunBinding binding; private ArrayList items; private HeterogeneousRecyclerAdapter adapter; @@ -65,17 +53,17 @@ public class OoniRunActivity extends AbstractActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActivityComponent().inject(this); - setContentView(R.layout.activity_oonirun); - ButterKnife.bind(this); - setSupportActionBar(toolbar); + binding = ActivityOonirunBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + setSupportActionBar(binding.toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); LinearLayoutManager layoutManager = new LinearLayoutManager(this); - recycler.setLayoutManager(layoutManager); - recycler.addItemDecoration(new DividerItemDecoration(this, layoutManager.getOrientation())); + binding.recycler.setLayoutManager(layoutManager); + binding.recycler.addItemDecoration(new DividerItemDecoration(this, layoutManager.getOrientation())); items = new ArrayList<>(); adapter = new HeterogeneousRecyclerAdapter<>(this, items); - recycler.setAdapter(adapter); + binding.recycler.setAdapter(adapter); manageIntent(getIntent()); } @@ -139,34 +127,34 @@ private void loadScreen(String mv, String tn, String ta){ } private void loadOutOfDate() { - title.setText(R.string.OONIRun_OONIProbeOutOfDate); - desc.setText(R.string.OONIRun_OONIProbeNewerVersion); - run.setText(R.string.OONIRun_Update); - icon.setImageResource(R.drawable.update); - iconBig.setImageResource(R.drawable.update); - iconBig.setVisibility(View.VISIBLE); - run.setOnClickListener(v -> { + binding.title.setText(R.string.OONIRun_OONIProbeOutOfDate); + binding.desc.setText(R.string.OONIRun_OONIProbeNewerVersion); + binding.run.setText(R.string.OONIRun_Update); + binding.icon.setImageResource(R.drawable.update); + binding.iconBig.setImageResource(R.drawable.update); + binding.iconBig.setVisibility(View.VISIBLE); + binding.run.setOnClickListener(v -> { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName()))); finish(); }); } private void loadSuite(AbstractSuite suite, List urls) { - icon.setImageResource(suite.getIcon()); - title.setText(suite.getTestList(preferenceManager)[0].getLabelResId()); - desc.setText(getString(R.string.OONIRun_YouAreAboutToRun)); + binding.icon.setImageResource(suite.getIcon()); + binding.title.setText(suite.getTestList(preferenceManager)[0].getLabelResId()); + binding.desc.setText(getString(R.string.OONIRun_YouAreAboutToRun)); if (urls != null) { for (String url : urls) { if (URLUtil.isValidUrl(url)) items.add(new TextItem(url)); } adapter.notifyTypesChanged(); - iconBig.setVisibility(View.GONE); + binding.iconBig.setVisibility(View.GONE); } else { - iconBig.setImageResource(suite.getIcon()); - iconBig.setVisibility(View.VISIBLE); + binding.iconBig.setImageResource(suite.getIcon()); + binding.iconBig.setVisibility(View.VISIBLE); } - run.setOnClickListener(v -> { + binding.run.setOnClickListener(v -> { RunningActivity.runAsForegroundService(OoniRunActivity.this, suite.asArray(),this::finish, preferenceManager); @@ -174,12 +162,12 @@ private void loadSuite(AbstractSuite suite, List urls) { } private void loadInvalidAttributes() { - title.setText(R.string.OONIRun_InvalidParameter); - desc.setText(R.string.OONIRun_InvalidParameter_Msg); - run.setText(R.string.OONIRun_Close); - icon.setImageResource(R.drawable.question_mark); - iconBig.setImageResource(R.drawable.question_mark); - iconBig.setVisibility(View.VISIBLE); - run.setOnClickListener(v -> finish()); + binding.title.setText(R.string.OONIRun_InvalidParameter); + binding.desc.setText(R.string.OONIRun_InvalidParameter_Msg); + binding.run.setText(R.string.OONIRun_Close); + binding.icon.setImageResource(R.drawable.question_mark); + binding.iconBig.setImageResource(R.drawable.question_mark); + binding.iconBig.setVisibility(View.VISIBLE); + binding.run.setOnClickListener(v -> finish()); } } From bcbb01c29d9a45c10a68f531e6671c8311f0f7e5 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Thu, 3 Aug 2023 17:49:04 +0100 Subject: [PATCH 13/33] Chore: Update `OverviewActivity` to `ViewBinding` --- .../ooniprobe/activity/OverviewActivity.java | 55 +++++++++---------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/OverviewActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/OverviewActivity.java index 415744384..d7b9c4997 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/OverviewActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/OverviewActivity.java @@ -5,18 +5,14 @@ import android.os.Bundle; import android.text.format.DateUtils; import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; import androidx.annotation.Nullable; -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.ActivityCompat; import androidx.core.text.TextUtilsCompat; import androidx.core.view.ViewCompat; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.PreferenceManager; +import org.openobservatory.ooniprobe.databinding.ActivityOverviewBinding; import org.openobservatory.ooniprobe.model.database.Result; import org.openobservatory.ooniprobe.test.suite.AbstractSuite; import org.openobservatory.ooniprobe.test.suite.ExperimentalSuite; @@ -27,20 +23,12 @@ import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; import ru.noties.markwon.Markwon; public class OverviewActivity extends AbstractActivity { private static final String TEST = "test"; - @BindView(R.id.toolbar) Toolbar toolbar; - @BindView(R.id.icon) ImageView icon; - @BindView(R.id.runtime) TextView runtime; - @BindView(R.id.lastTime) TextView lastTime; - @BindView(R.id.desc) TextView desc; - @BindView(R.id.customUrl) Button customUrl; - @BindView(R.id.run) Button run; + + ActivityOverviewBinding binding; private AbstractSuite testSuite; @Inject @@ -55,16 +43,16 @@ public static Intent newIntent(Context context, AbstractSuite testSuite) { getActivityComponent().inject(this); testSuite = (AbstractSuite) getIntent().getSerializableExtra(TEST); setTheme(testSuite.getThemeLight()); - setContentView(R.layout.activity_overview); - ButterKnife.bind(this); - setSupportActionBar(toolbar); + binding = ActivityOverviewBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + setSupportActionBar(binding.toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); setTitle(testSuite.getTitle()); - icon.setImageResource(testSuite.getIcon()); - customUrl.setVisibility(testSuite.getName().equals(WebsitesSuite.NAME) ? View.VISIBLE : View.GONE); + binding.icon.setImageResource(testSuite.getIcon()); + binding.customUrl.setVisibility(testSuite.getName().equals(WebsitesSuite.NAME) ? View.VISIBLE : View.GONE); if(testSuite.isTestEmpty(preferenceManager)){ - run.setAlpha(0.5F); - run.setEnabled(false); + binding.run.setAlpha(0.5F); + binding.run.setEnabled(false); } if (testSuite.getName().equals(ExperimentalSuite.NAME)) { String experimentalLinks = @@ -72,24 +60,31 @@ public static Intent newIntent(Context context, AbstractSuite testSuite) { "\n\n* [DNS Check](https://github.com/ooni/spec/blob/master/nettests/ts-028-dnscheck.md)" + "\n\n* [Tor Snowflake](https://ooni.org/nettest/tor-snowflake/) "+ String.format(" ( %s )",getString(R.string.Settings_TestOptions_LongRunningTest))+ "\n\n* [Vanilla Tor](https://github.com/ooni/spec/blob/master/nettests/ts-016-vanilla-tor.md) " + String.format(" ( %s )",getString(R.string.Settings_TestOptions_LongRunningTest)); - Markwon.setMarkdown(desc, getString(testSuite.getDesc1(), experimentalLinks)); + Markwon.setMarkdown(binding.desc, getString(testSuite.getDesc1(), experimentalLinks)); if (TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL) - desc.setTextDirection(View.TEXT_DIRECTION_RTL); + binding.desc.setTextDirection(View.TEXT_DIRECTION_RTL); } else - Markwon.setMarkdown(desc, getString(testSuite.getDesc1())); + Markwon.setMarkdown(binding.desc, getString(testSuite.getDesc1())); Result lastResult = Result.getLastResult(testSuite.getName()); if (lastResult == null) - lastTime.setText(R.string.Dashboard_Overview_LastRun_Never); + binding.lastTime.setText(R.string.Dashboard_Overview_LastRun_Never); else - lastTime.setText(DateUtils.getRelativeTimeSpanString(lastResult.start_time.getTime())); + binding.lastTime.setText(DateUtils.getRelativeTimeSpanString(lastResult.start_time.getTime())); + + setUpOnCLickListeners(); + } + + private void setUpOnCLickListeners() { + binding.run.setOnClickListener(view -> onRunClick()); + binding.customUrl.setOnClickListener(view -> customUrlClick()); } @Override protected void onResume() { super.onResume(); testSuite.setTestList((AbstractTest[]) null); testSuite.getTestList(preferenceManager); - runtime.setText(getString(R.string.twoParam, getString(testSuite.getDataUsage()), getString(R.string.Dashboard_Card_Seconds, testSuite.getRuntime(preferenceManager).toString()))); + binding.runtime.setText(getString(R.string.twoParam, getString(testSuite.getDataUsage()), getString(R.string.Dashboard_Card_Seconds, testSuite.getRuntime(preferenceManager).toString()))); } @Override @@ -98,13 +93,13 @@ public boolean onSupportNavigateUp() { return true; } - @OnClick(R.id.run) void onRunClick() { + void onRunClick() { if(!testSuite.isTestEmpty(preferenceManager)){ RunningActivity.runAsForegroundService(this, testSuite.asArray(), this::bindTestService, preferenceManager); } } - @OnClick(R.id.customUrl) void customUrlClick() { + void customUrlClick() { startActivity(new Intent(this, CustomWebsiteActivity.class)); } } From 6aa9fb2f6ef17b3e7d6c4ac9462ac9f784865181 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sat, 5 Aug 2023 17:04:28 +0100 Subject: [PATCH 14/33] Chore update to gradle version catalogs --- app/build.gradle | 131 +++++++++++++++++++------------------- app/jacoco.gradle | 2 +- applogger/build.gradle | 8 +-- build.gradle | 6 +- engine/build.gradle | 15 +++-- gradle/libs.versions.toml | 117 ++++++++++++++++++++++++++++++++++ 6 files changed, 197 insertions(+), 82 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/app/build.gradle b/app/build.gradle index ac15c07d7..4dcb38f3c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,14 +1,17 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} apply from: 'jacoco.gradle' android { - compileSdk 34 + compileSdk libs.versions.compileSdk.get().toInteger() ndkVersion '22.0.7026061' - defaultConfig { - applicationId 'org.openobservatory.ooniprobe' - minSdk 21 - targetSdk 34 + defaultConfig { + applicationId 'org.openobservatory.ooniprobe' + minSdk libs.versions.minSdk.get().toInteger() + targetSdk libs.versions.targetSdk.get().toInteger() versionName '3.8.3' versionCode 102 testInstrumentationRunner "org.openobservatory.ooniprobe.TestAndroidJUnitRunner" @@ -104,82 +107,76 @@ dependencies { implementation project(path: ':engine') // AndroidX - implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.lifecycle:lifecycle-process:2.5.1' - implementation 'androidx.preference:preference:1.2.0' - implementation 'com.google.android.material:material:1.6.1' - implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' - implementation 'com.google.guava:guava:30.1.1-android' - implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation libs.androidx.appcompat + implementation libs.androidx.constraintlayout + implementation libs.androidx.lifecycle.process + implementation libs.androidx.preference + implementation libs.androidx.localbroadcastmanager + implementation libs.androidx.legacy.support.v4 + +// Google + implementation libs.google.material + implementation libs.google.guava + implementation libs.google.gson // Third-party - annotationProcessor 'com.github.Raizlabs.DBFlow:dbflow-processor:4.2.4' - implementation 'com.github.Raizlabs.DBFlow:dbflow-core:4.2.4' - implementation 'com.github.Raizlabs.DBFlow:dbflow:4.2.4' + annotationProcessor libs.dbflow.processor + implementation libs.dbflow.core + implementation libs.dbflow.lib - implementation 'com.squareup.retrofit2:retrofit:2.9.0' - implementation 'com.squareup.retrofit2:converter-gson:2.9.0' - implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' + implementation libs.retrofit.lib + implementation libs.retrofit.converter.gson + implementation libs.retrofit.logging.interceptor - implementation 'com.jakewharton:butterknife:10.2.3' - annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' + implementation libs.butterknife.core + annotationProcessor libs.butterknife.compiler - implementation 'com.github.xanscale.LocalhostToolkit:app:19.05.01' - implementation 'com.airbnb.android:lottie:3.0.7' - implementation 'com.google.code.gson:gson:2.8.9' - implementation 'ru.noties:markwon:2.0.1' - implementation 'commons-io:commons-io:2.6' - //arcview to fragment_dashboard - implementation 'com.github.florent37:shapeofview:1.3.2' + implementation libs.xanscale.localhost.toolkit + implementation libs.lottie + implementation libs.markwon + implementation libs.commons.io + //arcview to fragment_dashboard + implementation libs.shapeofview // Flavor - fullImplementation platform('com.google.firebase:firebase-bom:26.3.0') - fullImplementation 'com.google.firebase:firebase-messaging' - fullImplementation 'ly.count.android:sdk:21.11.0' - fullImplementation 'io.sentry:sentry-android:6.3.0' - fullImplementation 'com.google.android.play:core:1.10.3' + fullImplementation platform(libs.google.firebase.bom) + fullImplementation libs.google.firebase.messaging + fullImplementation libs.countly.sdk + fullImplementation libs.sentry.android + fullImplementation libs.google.play.core // Dependency Injection - implementation 'com.google.dagger:dagger:2.36' - annotationProcessor 'com.google.dagger:dagger-compiler:2.36' + implementation libs.google.dagger + annotationProcessor libs.google.dagger.compiler // Logger implementation project(':applogger') // Testing - // Unit Testing - testImplementation 'junit:junit:4.13.2' - testImplementation 'androidx.test:core:1.4.0' - testImplementation 'androidx.test:runner:1.4.0' - testImplementation 'androidx.test:rules:1.4.0' - testImplementation 'org.mockito:mockito-core:4.6.1' - testImplementation 'org.mockito:mockito-inline:4.6.1' - testImplementation 'org.robolectric:robolectric:4.5.1' - testImplementation 'com.github.blocoio:faker:1.2.8' - testImplementation 'org.ooni:oonimkall:2023.07.18-162729' - testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.36' - - // Instrumentation Testing - androidTestImplementation 'tools.fastlane:screengrab:2.0.0' - androidTestImplementation 'com.github.blocoio:faker:1.2.8' - androidTestImplementation 'androidx.test:runner:1.4.0' - androidTestImplementation 'androidx.test:rules:1.4.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0' - androidTestImplementation('androidx.test.espresso:espresso-contrib:3.4.0') { - exclude group: 'com.android.support', module: 'appcompat' - exclude group: 'com.android.support', module: 'support-v4' - exclude module: 'recyclerview-v7' - } - androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0') { - exclude group: 'com.android.support', module: 'appcompat' - exclude group: 'com.android.support', module: 'support-v4' - exclude module: 'recyclerview-v7' - } - androidTestImplementation('com.schibsted.spain:barista:3.9.0') - androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.36" + // Unit Testing + testImplementation libs.junit4 + testImplementation libs.androidx.core + testImplementation libs.androidx.runner + testImplementation libs.androidx.rules + testImplementation libs.mockito.core + testImplementation libs.mockito.inline + testImplementation libs.robolectric + testImplementation libs.faker + testImplementation libs.ooni.oonimkall + testAnnotationProcessor libs.google.dagger.compiler + + // Instrumentation Testing + androidTestImplementation libs.fastlane.screengrab + androidTestImplementation libs.faker + androidTestImplementation libs.androidx.runner + androidTestImplementation libs.androidx.rules + androidTestImplementation libs.androidx.junit + androidTestImplementation libs.androidx.espresso.intents + androidTestImplementation libs.androidx.espresso.contrib + androidTestImplementation libs.androidx.espresso.core + androidTestImplementation libs.barista + androidTestAnnotationProcessor libs.google.dagger.compiler } static def versionCodeDate() { diff --git a/app/jacoco.gradle b/app/jacoco.gradle index 816940653..f75812752 100644 --- a/app/jacoco.gradle +++ b/app/jacoco.gradle @@ -1,7 +1,7 @@ apply plugin: 'jacoco' jacoco { - toolVersion '0.8.5' + toolVersion libs.versions.jacoco.get().toString() } task jacocoAndroidTestReport(type: JacocoReport) { diff --git a/applogger/build.gradle b/applogger/build.gradle index 2726a7647..424233927 100644 --- a/applogger/build.gradle +++ b/applogger/build.gradle @@ -4,11 +4,11 @@ plugins { } android { - compileSdk 31 + compileSdk libs.versions.compileSdk.get().toInteger() defaultConfig { - minSdk 16 - targetSdk 31 + minSdk libs.versions.minSdk.get().toInteger() + targetSdk libs.versions.targetSdk.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -32,5 +32,5 @@ android { } dependencies { - testImplementation 'junit:junit:+' + testImplementation libs.junit4 } diff --git a/build.gradle b/build.gradle index 1fcb28081..7a5b2861b 100644 --- a/build.gradle +++ b/build.gradle @@ -6,9 +6,9 @@ buildscript { maven { url "https://jitpack.io" } } dependencies { - classpath 'com.android.tools.build:gradle:7.4.1' - classpath 'com.google.gms:google-services:4.3.13' - classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21' + classpath libs.android.gradlePlugin + classpath libs.gms.googleServices + classpath libs.kotlin.gradlePlugin } } diff --git a/engine/build.gradle b/engine/build.gradle index 93facfd52..a64cced29 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -1,12 +1,13 @@ -apply plugin: 'com.android.library' +plugins { + id 'com.android.library' +} android { - compileSdkVersion 30 - buildToolsVersion "30.0.3" + compileSdk libs.versions.compileSdk.get().toInteger() defaultConfig { - minSdkVersion 19 - targetSdkVersion 30 + minSdk libs.versions.minSdk.get().toInteger() + targetSdk libs.versions.targetSdk.get().toInteger() } compileOptions { @@ -32,8 +33,8 @@ android { dependencies { // For the stable and dev app flavours we're using the library // build published at Maven Central. - stableImplementation 'org.ooni:oonimkall:2023.07.18-162729' - devImplementation 'org.ooni:oonimkall:2023.07.18-162729' + stableImplementation libs.ooni.oonimkall + devImplementation libs.ooni.oonimkall // For the experimental flavour, you need to compile your own // oonimkall.aar and put it into the ../engine-experimental dir diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..7ab027deb --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,117 @@ +[versions] +androidGradlePlugin = "7.4.1" +barista = "3.9.0" +countlySdk = "21.11.0" +faker = "1.2.8" +mockitoCore = "4.6.1" +robolectric = "4.5.1" +fastlaneScreengrab = "2.0.0" +sentryAndroid = "6.3.0" +xanscaleLocalhostToolkit = "19.05.01" +commonsIo = "2.6" +jacoco = "0.8.5" +kotlin = "1.6.21" + +# Android X +androidxCore = "1.4.0" +androidxAppCompat = "1.6.1" +androidxConstraintlayout = "2.1.4" +androidxLifecycleProcess = "2.5.1" +androidxPreference = "1.2.0" +androidxLocalbroadcastmanager = "1.1.0" +androidxLegacySupportV4 = "1.0.0" +androidxJunit = "1.1.3" +androidxEspressoCore = "3.4.0" + +# Google +googleGson = "2.8.9" +googleGuava = "30.1.1-android" +googleMaterial = "1.6.1" +googleDagger = "2.36" +googleFirebaseBon = "26.3.0" +googlePlaycore = "1.10.3" + +# OONI +compileSdk = "34" +lottie = "3.0.7" +markwon = "2.0.1" +shapeofview = "1.3.2" +targetSdk = "34" +minSdk = "21" +oonimkall = "2023.07.18-162729" + +junit = "4.13.2" +dbflow = "4.2.4" +retrofitCore = "2.9.0" +retrofitLoggingInterceptor = "4.9.1" +butterknifeCore = "10.2.3" + +# Firebase Services +# https://firebase.google.com/support/release-notes/android +gms-googleServices = "4.3.15" + +[libraries] +# Dependencies of the included build-logic +android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } +barista = { module = "com.schibsted.spain:barista", version.ref = "barista" } +countly-sdk = { module = "ly.count.android:sdk", version.ref = "countlySdk" } +faker = { module = "com.github.blocoio:faker", version.ref = "faker" } +robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" } +fastlane-screengrab = { module = "tools.fastlane:screengrab", version.ref = "fastlaneScreengrab" } +sentry-android = { module = "io.sentry:sentry-android", version.ref = "sentryAndroid" } +xanscale-localhost-toolkit = { module = "com.github.xanscale.LocalhostToolkit:app", version.ref = "xanscaleLocalhostToolkit" } +commons-io = { module = "commons-io:commons-io", version.ref = "commonsIo" } +kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } + +mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockitoCore" } +mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockitoCore" } + +butterknife-core = { module = "com.jakewharton:butterknife", version.ref = "butterknifeCore" } +butterknife-compiler = { module = "com.jakewharton:butterknife-compiler", version.ref = "butterknifeCore" } + +lottie = { module = "com.airbnb.android:lottie", version.ref = "lottie" } +markwon = { module = "ru.noties:markwon", version.ref = "markwon" } +retrofit-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofitCore" } +retrofit-logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "retrofitLoggingInterceptor" } +retrofit-lib = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofitCore" } + +dbflow-lib = { module = "com.github.Raizlabs.DBFlow:dbflow", version.ref = "dbflow" } +dbflow-core = { module = "com.github.Raizlabs.DBFlow:dbflow-core", version.ref = "dbflow" } +dbflow-processor = { module = "com.github.Raizlabs.DBFlow:dbflow-processor", version.ref = "dbflow" } + +androidx-core = { module = "androidx.test:core", version.ref = "androidxCore" } +androidx-rules = { module = "androidx.test:rules", version.ref = "androidxCore" } +androidx-runner = { module = "androidx.test:runner", version.ref = "androidxCore" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidxAppCompat" } +androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidxConstraintlayout" } +androidx-legacy-support-v4 = { module = "androidx.legacy:legacy-support-v4", version.ref = "androidxLegacySupportV4" } +androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "androidxLifecycleProcess" } +androidx-localbroadcastmanager = { module = "androidx.localbroadcastmanager:localbroadcastmanager", version.ref = "androidxLocalbroadcastmanager" } +androidx-preference = { module = "androidx.preference:preference", version.ref = "androidxPreference" } +androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidxJunit" } +androidx-espresso-contrib = { module = "androidx.test.espresso:espresso-contrib", version.ref = "androidxEspressoCore" } +androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidxEspressoCore" } +androidx-espresso-intents = { module = "androidx.test.espresso:espresso-intents", version.ref = "androidxEspressoCore" } + +google-play-core = { module = "com.google.android.play:core", version.ref = "googlePlaycore" } +google-gson = { module = "com.google.code.gson:gson", version.ref = "googleGson" } +google-guava = { module = "com.google.guava:guava", version.ref = "googleGuava" } +google-material = { module = "com.google.android.material:material", version.ref = "googleMaterial" } +google-dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "googleDagger" } +google-dagger = { module = "com.google.dagger:dagger", version.ref = "googleDagger" } +google-firebase-messaging = { module = "com.google.firebase:firebase-messaging"} +google-firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "googleFirebaseBon" } + +junit4 = { module = "junit:junit", version.ref = "junit" } +gms-googleServices = { module = "com.google.gms:google-services", version.ref = "gms-googleServices" } +ooni-oonimkall = { module = "org.ooni:oonimkall", version.ref = "oonimkall" } +shapeofview = { module = "com.github.florent37:shapeofview", version.ref = "shapeofview" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } +android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } +android-test = { id = "com.android.test", version.ref = "androidGradlePlugin" } + +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } + +gms-googleServices = { id = "com.google.gms.google-services", version.ref = "gms-googleServices"} \ No newline at end of file From 9362e53600421143272047ca69b529440d6b15fa Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sun, 6 Aug 2023 14:53:16 +0100 Subject: [PATCH 15/33] Updated countly initialization to stop use of `deprecated API` --- .../openobservatory/ooniprobe/common/ThirdPartyServices.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/full/java/org/openobservatory/ooniprobe/common/ThirdPartyServices.java b/app/src/full/java/org/openobservatory/ooniprobe/common/ThirdPartyServices.java index 80b6c731d..bfd47d05e 100644 --- a/app/src/full/java/org/openobservatory/ooniprobe/common/ThirdPartyServices.java +++ b/app/src/full/java/org/openobservatory/ooniprobe/common/ThirdPartyServices.java @@ -20,6 +20,7 @@ import io.sentry.android.core.SentryAndroid; import ly.count.android.sdk.Countly; import ly.count.android.sdk.CountlyConfig; +import ly.count.android.sdk.messaging.CountlyConfigPush; import ly.count.android.sdk.messaging.CountlyPush; public class ThirdPartyServices { @@ -48,7 +49,9 @@ public static void initCountly(Application app) { public static void registerPush(Application app){ if (Countly.sharedInstance().isInitialized()) { - CountlyPush.init(app, BuildConfig.DEBUG ? Countly.CountlyMessagingMode.TEST : Countly.CountlyMessagingMode.PRODUCTION); + CountlyConfigPush countlyConfigPush = new CountlyConfigPush(app, BuildConfig.DEBUG ? Countly.CountlyMessagingMode.TEST : Countly.CountlyMessagingMode.PRODUCTION) + .setProvider(Countly.CountlyMessagingProvider.FCM); + CountlyPush.init(countlyConfigPush); NotificationUtility.setChannel(app, CountlyPush.CHANNEL_ID, app.getString(R.string.Settings_Notifications_Label), true, true, true); ThirdPartyServices.setToken(app); } From 9f033e76478d5e331e02ebad978f32c751549eeb Mon Sep 17 00:00:00 2001 From: Norbel AMBANUMBEN Date: Mon, 7 Aug 2023 12:08:15 +0100 Subject: [PATCH 16/33] Chore: Add `workflow` to build test apk (#596) ## Proposed Changes - Add a `workflow` to build APK to facilitate reviews. --- .github/workflows/archive.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/archive.yml diff --git a/.github/workflows/archive.yml b/.github/workflows/archive.yml new file mode 100644 index 000000000..d41537923 --- /dev/null +++ b/.github/workflows/archive.yml @@ -0,0 +1,19 @@ +# archive creates and publishes an apk for testing +name: archive +on: [push] +jobs: + build: + runs-on: macos-latest + steps: + - uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'temurin' + - name: checkout + uses: actions/checkout@v2 + - run: ./gradlew clean assembleDevFullRelease + - name: uploads dev apk + uses: actions/upload-artifact@v3 + with: + name: dev-apk + path: app/build/outputs/apk/devFull/release \ No newline at end of file From e30c0ef6d704fff70a17d04bbaefaba1b9023b1e Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Fri, 11 Aug 2023 17:56:55 +0100 Subject: [PATCH 17/33] Added translations for `vi` and `my` --- app/src/main/res/values-my/strings.xml | 533 ++++++++++++++++++++++ app/src/main/res/values-vi/strings.xml | 533 ++++++++++++++++++++++ app/src/main/res/values/untraslatable.xml | 4 + 3 files changed, 1070 insertions(+) create mode 100644 app/src/main/res/values-my/strings.xml create mode 100644 app/src/main/res/values-vi/strings.xml diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml new file mode 100644 index 000000000..10248fce7 --- /dev/null +++ b/app/src/main/res/values-my/strings.xml @@ -0,0 +1,533 @@ + + + OONI Probe + OONI Probe ဆိုတာ ဘာလဲ။ + သင့်အက်ပ်သည် အင်တာနက် ဆင်ဆာဖြတ်တောက်မှုကို တိုင်းတာရန် သင့်အက်ပ်။\n\nဝဘ်ဆိုက်များနှင့် ဆိုရှယ်မီဒီယာအက်ပ်များကို ပိတ်ဆို့ နေပါသလား။ သင့်အင်တာနက် ချိတ်ဆက်မှုသည် ပုံမှန်မဟုတ်ဘဲ နှေးနေပါသလား။\n\n၄င်းအကြောင်းအရာတို့ကို သိရှိရန် OONI Probe ကိုဖွင့်ပါ။ + ရပြီ + ကြိုတင်အသိပေးသည်။ + OONI ဒေတာကို ပွင့်လင်းမြင်သာစွာ ထုတ်ဝေထားပြီး သင့်ကွန်ရက် အချက်အလက် များကိုလည်း ပါဝင်မည် ဖြစ်သည်။ + သင့် အင်တာနက် အသုံးပြုမှုကို စောင့်ကြည့်နေသူတိုင်း (အစိုးရ သို့မဟုတ် အင်တာနက် ဝန်ဆောင်မှု ပံ့ပိုးသူ) သည် OONI Probe အား သင် အသုံးပြုနေကြောင်း တွေ့မြင်ရမည်။ + တားမြစ်ထားသော ဝဘ်ဆိုဒ်များကို သင် စမ်းသပ်နိုင်သည် (သို့သော် စမ်းသပ်မည့် ဆိုဒ်များကို သင် ရွေးချယ်နိုင်သည်)။ + နားလည်သည် + ပိုမိုလေ့လာရန် + လျှပ်တပြက် ဉာဏ်စမ်း + မှန် + မှားသည် + နောက်သို့ + ဆက်လုပ်မည် + မေးခွန်း ၁/၂ + တစ်စုံတစ်ယောက်သည် ကျွန်ုပ်၏အင်တာနက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နေပါက၊ ကျွန်ုပ်သည် OONI Probe ကို အသုံးပြုနေကြောင်း ၎င်းတို့ မြင်တွေ့ရမည် ဖြစ်သည်။ + သတိပေးချက် + OONI Probe သည် ကိုယ်ရေးလုံခြုံမှု ကိရိယာတစ်ခု မဟုတ်ပါ။ သင့် အင်တာနက် လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နေသူတိုင်းသည် သင်အသုံးပြုနေသည့် ဆော့ဖ်ဝဲလ်ကို သိပါလိမ့်မည်။ + မေးခွန်း ၂/၂ + OONI Probe ကို ကျွန်ုပ်အသုံးပြုတိုင်း၊ ကျွန်ုပ် စုဆောင်းထားသော ကွန်ရက်ဒေတာကို အလိုအလျောက် ထုတ်ဝေပါမည်။ + သတိပေးချက် + အင်တာနက် ဆင်ဆာဖြတ်တောက်မှု ပွင့်လင်းမြင်သာရေး တိုးမြင့်စေရန် OONI Probe အသုံးပြုသူများ အားလုံး၏ ကွန်ရက် ဒေတာများအား အလိုအလျောက် ထုတ်ဝေပါမည် (ဆက်တင်တွင် ရွေးချယ်ထားပါက)။ + အလိုအလျောက် စမ်းသပ်ခြင်း + နေ့စဉ် အင်တာနက် ဆင်ဆာဖြတ်တောက်မှုကို တိုင်းတာရန်အတွက် OONI Probe သည် စမ်းသပ်မှုများကို အခါအားလျော်စွာ လုပ်ဆောင်နိုင်စေရန် အလိုအလျောက် စမ်းသပ်မှုကို ဖွင့်ပါ။\n\nစိတ်မပူပါနှင့်၊ ဘက်ထရီ အသုံးပြုမှုကို ကျွန်ုပ်တို့ သတိထားပါမည်။\n\nဆက်တင်များမှ အလိုအလျောက် စမ်းသပ်ခြင်းကို အချိန်မရွေး ပိတ်နိုင်သည်။ + ပျက်စီးမှု သတင်းပို့ခြင်း + OONI Probe ပိုမိုကောင်းမွန်စေရန်အတွက် အက်ပ်သည် ကောင်းမွန်စွာ အလုပ်မလုပ်သည့်အခါ အမည်မသိ ပျက်စီးမှု အစီရင်ခံစာများကို စုဆောင်းလိုပါသည်။\n\nပျက်စီးမှု အစီရင်ခံစာများကို OONI ဖွံ့ဖြိုးတိုးတက်ရေး အဖွဲ့ထံ တင်သွင်းခြင်း လုပ်ငန်းတွင် သင် ပါဝင်လိုပါသလား။ + ဟုတ်တယ် + မဟုတ်ပါ + နဂိုမူလ ဆက်တင်များ + ကျွန်ုပ်တို့ ကောက်ယူစုဆောင်း၍ ဖြန့်ဝေသည် - + နိုင်ငံကုဒ် (ဥပမာ - အီတလီအတွက် IT) + ကွန်ရက် သတင်းအချက်အလက် (အလိုအလျောက်စနစ် နံပတ်အပါအဝင်) + စမ်းသပ်ချိန်နှင့် ရက်စွဲ + သင်၏ IP လိပ်စာ သို့မဟုတ် အခြားသော ပုဂ္ဂိုလ်ရေးအရ ခွဲခြား သိမြင်နိုင်သော အချက်အလက်များကို ထုတ်ဝေခြင်းမပြုရန် ကျွန်ုပ်တို့ အကောင်းဆုံး လုပ်ဆောင်ပါသည်။ [OONI ၏ ဒေတာမူဝါဒ](https://ooni.org/about/data-policy/) တွင် ပိုမိုလေ့လာပါ။ + OONI Probe တိုးတက်စေရေးအတွက် ကျွန်ုပ်တို့အားကူညီနိုင်ရန် \"အိုကေ\" ကို နှိပ်၍ ပျက်စီးမှု အစီရင်ခံစာများကို မျှဝေနိုင်သည်။ + သွားကြစို့ + နဂိုမူလများကို ပြောင်းမည် + ဒက်ရှ်ဘုတ် + စမ်းမည် + အဖြေမရှိ + စမ်းမည် + နောက်ဆုံး စမ်းသပ်မှု - + ခန့်မှန်းထားသည် - + ဝဘ်ဆိုဒ်များ ရွေးချယ်ရန် + စမ်းသပ်နေသည် - + ခန့်မှန်း ကျန်ရှိချိန် - + %1$s စက္ကန့် + စမ်းသပ်မှုကို ပြင်ဆင်နေသည် + ETA တွက်ချက်ခြင်း + မှတ်တမ်း ပြမည် + မှတ်တမ်း ပိတ်မည် + စမ်းသပ်မှုကို ရပ်နေသည်... + လက်ရှိ စောင့်ဆိုင်းနေသော စမ်းသပ်မှုများကို အပြီးသတ်နေသည်၊ ကျေးဇူးပြု၍ စောင့်ပါ... + အသုံးပြုနေသော ပရောက်စီ + နောက်ထပ် ရွေးချယ်စရာများအတွက် ကတ်ကို နှိပ်ပါ + ~%1$ss + ဝဘ်ဆိုဒ်များ ပိတ်ဆို့ခြင်းကို စမ်းသပ်ပါ\n + OONI ၏ [ဝဘ်ချိတ်ဆက်မှု စမ်းသပ်ခြင်း](https://ooni.org/nettest/web-connectivity/) ကို အသုံးပြု၍ ဝဘ်ဆိုဒ်များအား ပိတ်ဆို့ထားခြင်းရှိ၊ မရှိ စစ်ဆေးပါ။\n\nစမ်းမည် ခလုတ်ကို နှိပ်တိုင်း Citizen Lab ၏ [ဂလိုဘယ်](https://github.com/citizenlab/test-lists/blob/master/lists/global.csv) နှင့် [country-specific](https://github.com/citizenlab/test-lists/tree/master/lists) စမ်းသပ်မှု စာရင်းများမှ ကွဲပြားသော ဝဘ်ဆိုဒ်များကို သင် စမ်းသပ်ခြင်း ဖြစ်သည်။\n\nသင်ရွေးချယ်သည့် ဆိုဒ်များကို စမ်းသပ်ရန်၊ ဝဘ်ဆိုဒ်များ ရွေးချယ်မည် ခလုတ်ကို နှိပ်ပါ သို့မဟုတ် ဤကတ်၏ ဆက်တင်များမှ တစ်ဆင့် ဆိုဒ်များ၏ အမျိုးအစားများကို ရွေးချယ်ပါ။\n\nဤစမ်းသပ်မှုသည် ဝဘ်ဆိုက်များကို DNS ကစားခြင်း၊ TCP/IP ပိတ်ဆို့ခြင်း သို့မဟုတ် ပွင့်လင်းမြင်သာသော HTTP ပရောက်စီ ဖြင့် ပိတ်ဆို့ခြင်း ရှိ၊ မရှိ တိုင်းတာ စစ်ဆေးသည်။\nသင့် ရလဒ်များအား [OONI Explorer](https://explorer.ooni.org/world/) နှင့် [OONI API](https://api.ooni.io/) တွင် ထုတ်ပြန်ပေးပါမည်။ + OONI ၏ [ဝဘ်ချိတ်ဆက်မှုစမ်းသပ်ခြင်း](https://ooni.org/nettest/web-connectivity/) ကို အသုံးပြု၍ ဝဘ်ဆိုဒ်များအား ပိတ်ဆို့ထားခြင်းရှိ၊ မရှိ စစ်ဆေးပါ။\n\nCitizen Lab ၏ [ဂလိုဘယ်](https://github.com/citizenlab/test-lists/blob/master/lists/global.csv) နှင့် [country-specific](https://github.com/citizenlab/test-lists/tree/master/lists) စမ်းသပ်မှု စာရင်းများ အပါအဝင် ဝဘ်ဆိုဒ်များကို စမ်းသပ်ရမည်။ \n\nဤစမ်းသပ်မှုသည် ဝဘ်ဆိုက်များကို DNS ဆော့ကစားခြင်း၊ TCP/IP ပိတ်ဆို့ခြင်း သို့မဟုတ် ပွင့်လင်းမြင်သာသော HTTP ပရောက်စီ ဖြင့် ပိတ်ဆို့ခြင်း ရှိ၊မရှိ တိုင်းတာသည်။\n\nသင့်ရလဒ်များအား [OONI Explorer](https://explorer.ooni.org/) နှင့် [OONI API](https://api.ooni.io/) တွင် ထုတ်ပြန်ပေးမည်။ + သင့် ကွန်ရက်အမြန်နှုန်းနှင့် စွမ်းဆောင်ရည်ကို စမ်းသပ်ပါ + [NDT] (https://ooni.org/nettest/ndt/) စမ်းသပ်မှုကို သုံး၍ သင်၏ကွန်ရက် အမြန်နှုန်းနှင့် စွမ်းဆောင်ရည်ကို တိုင်းတာပါ။\n\n[DASH] (https://ooni.org/nettest/dash/) စမ်းသပ်မှုကို သုံး၍ ဗီဒီယိုထုတ်လွှင့်ခြင်း စွမ်းဆောင်ရည်ကို တိုင်းတာပါ။\n\nဤစစ်ဆေးမှုများသည် သင့်ကွန်ရက် အမြန်နှုန်းပေါ်မူတည်၍ ဒေတာကို အသုံးပြုကြသည်။\n\nသင့် ရလဒ်များအား [OONI Explorer](https://explorer.ooni.org/world/) နှင့် [OONI API](https://api.ooni.io/) တွင် ထုတ်ဝေပါမည်။\n\nငြင်းဆိုချက် - ဤစစ်ဆေးမှုများသည် ပြင်ပ ဆာဗာများပေါ်တွင် အားကိုးပါသည်။ ထို့ကြောင့် သင်၏ IP လိပ်စာကို စုဆောင်းမည်မဟုတ်ကြောင်း ကျွန်ုပ်တို့ အာမ မခံနိုင်ပါ။ + ဤကတ်တွင် စမ်းသပ်မှုများကို လုပ်ဆောင်ခြင်းဖြင့် သင်သည် -\n\n\n- သင့် ကွန်ရက်၏ အမြန်နှုန်းနှင့် စွမ်းဆောင်ရည်ကို တိုင်းတာခြင်း ([NDT](https://ooni.org/nettest/ndt/) စမ်းသပ်မှု)\n- ဗီဒီယိုထုတ်လွှင့်ခြင်း စွမ်းဆောင်ရည်ကို တိုင်းတာခြင်း ([DASH](https://ooni.org/nettest/dash/) စမ်းသပ်မှု)\n\n- သင့်ကွန်ရက်တွင် [middlebox နည်းပညာများ](https://ooni.org/support/glossary/#middlebox) ရှိ၊ မရှိစစ်ဆေးပါ ([HTTP Invalid Request Line](https://ooni.org/nettest/http-invalid -request-line/) နှင့် [HTTP Header Field Manipulation](https://ooni.org/nettest/http-header-field-manipulation/) စမ်းသပ်မှုများ)\n\nဤစစ်ဆေးမှုများသည် သင့်ကွန်ရက် အမြန်နှုန်းပေါ်မူတည်၍ ဒေတာကို အသုံးပြုကြသည်။ \n\nသင်၏ စမ်းသပ်မှုရလဒ်များကို [OONI Explorer](https://explorer.ooni.org/) နှင့် [OONI API](https://api.ooni.io/) တွင် ထုတ်ပြန်မည်ဖြစ်ပါသည်။\n\n**ငြင်းဆိုချက် - ** အဆိုပါ [NDT](https://ooni.org/nettest/ndt/) နှင့် \n[DASH](https://ooni.org/nettest/dash/) စမ်းသပ်မှုများကို [Measurement Lab (M-Lab)](https://www.measurementlab.net/) \nမှ ပံ့ပိုးပေးသော ပြင်ပဆာဗာများက တဆင့် ဆောင်ရွက်ခြင်း ဖြစ်သည်။ ဤ စမ်းသပ်မှုများကို ဆောင်ရွက်လျှင် OONI Probe ဆက်တင်\nနှင့် မသက်ဆိုင်ဘဲ သင့် IP လိပ်စာအား M-Lab က ကောက်ယူကာ ထုတ်ပြန်မည်။ M-Lab ၏ [ကိုယ်ရေးလုံခြုံမှု ကြေညာချက်](https://www.measurementlab.net/privacy/) မှတဆင့် ၎င်း၏ ဒေတာစီမံခန့်ခွဲမှုအကြောင်းကို ပိုမိုသိရှိနိုင်သည်။ + သင့် ကွန်ရက်ရှိ middleboxes ကို ရှာဖွေရန် + အင်တာနက် ဝန်ဆောင်မှုပေးသူများသည် ကွန်ရက် ချိတ်ဆက်ခြင်းဆိုင်ရာ ရည်ရွယ်ချက်အမျိုးမျိုးအတွက် (caching ကဲ့သို့) အတွက် ကွန်ရက်သုံးပစ္စည်းများ (middleboxes) ကို မကြာခဏ အသုံးပြုကြသည်။ တခါတရံ ဤ middleboxes ကို အင်တာနက်ဆင်ဆာဖြတ်တောက်ခြင်းနှင့်/ သို့မဟုတ် စောင့်ကြည့်ခြင်းအား အကောင်အထည်ဖော်ရန် အသုံးပြုသည်။\n\nOONI ၏ [HTTP မဆီလျော်သော တောင်းဆိုမှုလိုင်း](https://ooni.org/nettest/http-invalid-request-line/) နှင့် [HTTP Header Field Manipulation](https://ooni.org/nettest/http-header-field-manipulation/) စမ်းသပ်မှုများကို သုံး၍ သင့်ကွန်ရက်အတွင်းရှိ middleboxes ကို ရှာနိုင်သည်။ \n\nသင့်ရလဒ်များအား [OONI Explorer](https://explorer.ooni.org/world/) နှင့် [OONI API](https://api.ooni.io/) တွင် ထုတ်ပြန်ပေးပါမည်။ + လက်ငင်း စာတိုပေးပို့ခြင်း အက်ပ်များ ပိတ်ဆို့ခြင်းအား စမ်းသပ်မည် + [WhatsApp](https://ooni.org/nettest/whatsapp/)၊ [Facebook Messenger](https://ooni.org/nettest/facebook-messenger/)၊ [Telegram](https://ooni.org/nettest/telegram/) နှင့် [Signal](https://ooni.org/nettest/signal) တို့ကို ပိတ်ဆို့ထားခြင်း ရှိ/မရှိ စစ်ဆေးမည်။\n\nသင့် ရလဒ်များအား [OONI Explorer](https://explorer.ooni.org/world/) နှင့် [OONI API](https://api.ooni.io/) တွင် ထုတ်ဝေပါမည်။ + ဆင်ဆာရှောင်တိမ်း ကိရိယာများကို ပိတ်ဆို့ စမ်းသပ်မည် + [Psiphon](https://ooni.org/nettest/psiphon/)၊ [Tor](https://ooni.org/nettest/tor/) သို့မဟုတ် [RiseupVPN](https://ooni.org/nettest/riseupvpn/) တို့ကို ပိတ်ဆို့ထားခြင်း ရှိ/မရှိ စစ်ဆေးရန်\nသင့် ရလဒ်များအား [OONI Explorer](https://explorer.ooni.org/) နှင့် [OONI API](https://api.ooni.io/) တွင် ထုတ်ပြန်ပေးပါမည်။ + စမ်းသပ်မှုအသစ်များကို လုပ်ဆောင်ရန် + OONI အဖွဲ့မှ ဖန်တီးထားသော အောက်ပါ စမ်းသပ်မှုအသစ်များကို လုပ်ဆောင်မည်\n%1$s\n\nသင့်ရလဒ်များကို [OONI Explorer](https://explorer.ooni.org/) နှင့် [OONI API](https://api.ooni.io/) တွင် ထုတ်ဝေပါမည်။ + အောက်ပါ စမ်းသပ်မှုများကို အလိုအ‌လျောက် စမ်းသပ်မှု၏ အစိတ်အပိုင်း အဖြစ်သာ ဆောင်ရွက်မည် - + ပယ်ဖျက်ထားသော စမ်းသပ်မှုများ\n + ဂစ်ဂါဘစ်/စက္ကန့် + မဂ္ဂါဘစ်/စက္ကန့် + ကီလိုဘစ်/စက္ကန့် + မီလီစက္ကန့် + မရရှိနိုင်ပါ + မသိ + စမ်းသပ်မှု ရလဒ်များ + စမ်းသပ်မှု ရလဒ်များ + စမ်းသပ်မှုများ + ကွန်ရက်များ + ဒေတာအသုံးပြုမှု + စမ်းသပ်မှုများ စစ်ထုတ်ရန် + စမ်းသပ်မှုအားလုံး + ဝဘ်ဆိုဒ်များ + Middleboxes + စွမ်းဆောင်ရည် + ချက်ခြင်း စာတိုပေးပို့ခြင်း\n + ရှောင်တိမ်းခြင်း + စမ်းသပ် လေ့လာနေဆဲ + စမ်းသပ်မှု မရှိသေးပါ။ စမ်းသပ်မှုတစ်ခုကို လုပ်ဆောင် ကြည့်လိုက်ပါ။ + %1$s ပိတ်ဆို့ထားသည် + %1$s ပိတ်ဆို့ထားသည် + %1$s စမ်းသပ်ခဲ့သည် + %1$s စမ်းသပ်ခဲ့သည် + စစ်ဆေး တွေ့ရှိခဲ့သည် + ရှာမတွေ့ပါ + မအောင်မြင်ပါ + %1$s ပိတ်ဆို့ထားသည် + %1$s ပိတ်ဆို့ထားသည် + %1$s အသုံးပြုနိုင်သည် + %1$s အသုံးပြုနိုင်သည် + %1$s ပိတ်ဆို့ထားသည် + %1$s ပိတ်ဆို့ထားသည် + %1$s ရရှိနိုင်သည် + %1$s ရရှိနိုင်သည် + မပြည့်စုံသော ရလဒ် + ပြဿနာ + တိုင်းတာမှုတွင် ပြဿနာ ရှိသည် + ရလဒ်များကို တင်ထားခြင်း မရှိပါ + နေ့စွဲ နှင့် အချိန် + ကွန်ရက် + နိုင်ငံ + ဒေတာအသုံးပြုမှု + စုစုပေါင်း လုပ်ဆောင်ချိန် + ဝိုင်ဖိုင် + မိုဘိုင်းဒေတာ + အင်တာနက်မရှိပါ + မအောင်မြင်ပါ + စမ်းသပ်ခဲ့သည် + စမ်းသပ်ခဲ့သည် + ပိတ်ဆို့ထားသည် + ပိတ်ဆို့ထားသည် + ဝဘ်ဆိုဒ် + ဝဘ်ဆိုဒ်များ + အသုံးပြုနိုင်သည် + အသုံးပြုနိုင်သည် + ဗီဒီယို + အရည်အသွေး + အပ်လုဒ် + ဒေါင်းလုဒ်လုပ်မည်\n + ပို့ပါ + ရှာတွေ့သည် + ရှာမတွေ့ပါ + မအောင်မြင်ပါ + စမ်းသပ်ခဲ့သည် + စမ်းသပ်ခဲ့သည် + ပိတ်ဆို့ထားသည် + ပိတ်ဆို့ထားသည် + အသုံးပြုနိုင်သည် + အသုံးပြုနိုင်သည် + အက်ပ် + အက်ပ်များ + စမ်းသပ်ခဲ့သည် + စမ်းသပ်ခဲ့သည် + ပိတ်ဆို့ထားသည် + ပိတ်ဆို့ထားသည် + အလုပ်လုပ်နေသည် + အလုပ်လုပ်နေသည် + ကိရိယာ + ကိရိယာများ + လုပ်ဆောင်ချိန် + နည်းစနစ် + ကြည့်ရှုမှု မှတ်တမ်း + ဒေတာ + Explorer URL ကို ကူးမည် + Explorer URL ကို မျှဝေမည်\n + Clipboard ထဲသို့ ကူးမည် + OONI Explorer တွင် ဖော်ပြရန် + မအောင်မြင်ပါ + သင်သည် ဤစမ်းသပ်မှုကို ထပ်မံ လုပ်ဆောင်နိုင်သည် + ထပ်ကြိုးစားပါ + ဤစမ်းသပ်မှု မည်သို့ အလုပ်လုပ်ပုံကို [ဤနေရာ](%1$s) တွင် လေ့လာပါ။ + အသုံးပြုနိုင်သည် + %1$s ကို အသုံးပြုနိုင်သည်။ + ပိတ်ဆို့ခံရဖွယ် ရှိသည် + %1$s%2$s ဖြင့် ပိတ်ဆို့ထားဖွယ်ရှိသည်။\n\nမှတ်ချက် - မှားယွင်းသော အကောင်းမြင်မှုများ ဖြစ်နိုင်သည်။ [ဤနေရာတွင်](https://ooni.org/support/faq/#what-are-false-positives) ပိုမိုလေ့လာပါ။\n + ဆင်ဆာဖြတ်တောက်မှုအား ရှောင်တိမ်းခြင်း + **DNS ကစားခြင်း** + ** TCP/IP အခြေခံ ပိတ်ဆို့ခြင်း** + **HTTP ပိတ်ဆို့ခြင်း (ပိတ်ဆို့ထားသည့် စာမျက်နှာတစ်ခုကို မြင်ရနိုင်သည်)** + **HTTP ပိတ်ဆို့ခြင်း (HTTP တောင်းဆိုမှုများ မအောင်မြင်ပါ)** + မိုဘိုင်းအက်ပ် + အိုကေ + မအောင်မြင်ပါ + WhatsApp ဝဘ် + အိုကေ + မအောင်မြင်ပါ + မှတ်ပုံတင်မည်\n + အိုကေ + မအောင်မြင်ပါ + အလုပ်လုပ်နေသည် + ဤစမ်းသပ်မှုသည် WhatsApp ၏ အဆုံးမှတ်များ၊ မှတ်ပုံတင်ခြင်း ဝန်ဆောင်မှုနှင့် ဝဘ်အင်တာဖေ့စ် (web.whatsapp.com) တို့နှင့် အောင်မြင်စွာ ချိတ်ဆက် ထားသည်။ + ပိတ်ဆို့ခံရဖွယ် ရှိသည် + WhatsApp ကို ပိတ်ဆို့ထားပုံ ရသည်။ + မိုဘိုင်းဖုန်း အက်ပ်\n + အိုကေ + မအောင်မြင်ပါ + တယ်လီဂရမ် ဝဘ် + အိုကေ + မအောင်မြင်ပါ + အလုပ်လုပ်နေသည် + ဤစမ်းသပ်မှုသည် Telegram ၏ အဆုံးမှတ်များနှင့် ဝဘ်အင်တာဖေ့စ် (web.telegram.org) နှင့် အောင်မြင်စွာ ချိတ်ဆက်ထားသည်။ + ပိတ်ဆို့ခံရဖွယ် ရှိသည် + Telegram ကို ပိတ်ဆို့ထားပုံ ရသည်။ + TCP ချိတ်ဆက်မှုများ + အိုကေ + မအောင်မြင်ပါ + DNS ရှာဖွေမှုများ + အိုကေ + မအောင်မြင်ပါ + အလုပ်လုပ်နေသည် + ဤစမ်းသပ်မှုသည် Facebook ၏ endpoint များနှင့် အောင်မြင်စွာ ချိတ်ဆက်ပြီး Facebook IP လိပ်စာများအား ဖြေရှင်းခဲ့သည်။ + ပိတ်ဆို့ခံရဖွယ် ရှိသည် + Facebook Messenger ကို ပိတ်ဆို့ထားပုံ ရသည်။ + ပိတ်ဆို့ခံရဖွယ် ရှိသည် + Signal ကို ပိတ်ဆို့ထားပုံ ရသည်။ + အလုပ်လုပ်နေသည် + ဤစမ်းသပ်မှုသည် Signal ၏ endpoints နှင့် အောင်မြင်စွာ ချိတ်ဆက်ထားသည်။ + middleboxes ကို ရှာမတွေ့ပါ + ကျွန်ုပ်တို့၏ ဆာဗာများနှင့် ဆက်သွယ်သောအခါတွင် ကွန်ရက် ကွဲလွဲမှုကို မတွေ့ရှိရပါ။ + ကွန်ရက် ကစားခြင်း + ကျွန်ုပ်တို့၏ ထိန်းချုပ်မှုဆာဗာများကို ဆက်သွယ်သည့်အခါ ကွန်ရက် အသွားအလာကို ခြယ်လှယ်ထားသည်။\n\nဆိုလိုသည်မှာ ဆင်ဆာနှင့်/သို့မဟုတ် စောင့်ကြည့်ခြင်းအတွက် တာဝန်ရှိနိုင်သည့် middlebox တစ်ခု သင့်ကွန်ရက်တွင် ရှိနေနိုင်သည်ဟု ဆိုလိုသည်။ + middleboxes အား မတွေ့ရှိပါ + ကျွန်ုပ်တို့၏ ဆာဗာများနှင့် ဆက်သွယ်သောအခါတွင် ကွန်ရက် ကွဲလွဲမှုကို မတွေ့ရှိရပါ။ + ကွန်ရက်ကို လက်ဆော့ခြင်း + ကျွန်ုပ်တို့၏ ထိန်းချုပ်မှုဆာဗာများကို ဆက်သွယ်သည့်အခါ ကွန်ရက် အသွားအလာကို ခြယ်လှယ်ထားသည်။\n\nဆိုလိုသည်မှာ ဆင်ဆာနှင့်/သို့မဟုတ် စောင့်ကြည့်ခြင်းအတွက် တာဝန်ရှိနိုင်သည့် သင့် ကွန်ရက်တွင် middlebox တစ်ခု ရှိနေနိုင်သည်ဟု ဆိုလိုသည်။ + သင်ပို့ခဲ့သည် + သင် လက်ခံရရှိခဲ့သည် + အပ်လုဒ် + ဒေါင်းလုဒ်လုပ်မည် + Ping + ဆာဗာ + ပြန်ပို့မှုနှုန်း + ကောင်းစွာ အလုပ်မလုပ်ပါ + ပျမ်းမျှ Ping + Max Ping ခန့်မှန်းမှု + MSS + အချိန်ကုန်သွားသည် + ယာယီ သိမ်းစရာ မလိုဘဲ %1$s အထိ ထုတ်လွှင့် နိုင်ပါသည်။ + အလယ်အလတ် ဘစ်နှုန်း + Playout ကြန့်ကြာခြင်း + ပိတ်ဆို့ခံရဖွယ် ရှိသည် + အလုပ်လုပ်နေသည် + [Psiphon](https://psiphon.ca/) ကို ပိတ်ဆို့ ထားပုံ ရသည်။\n + ကျွန်ုပ်တို့သည် Psiphon ချိတ်ဆက်မှု တစ်ခုကို အောင်မြင်စွာ စတင်နိုင်ခဲ့သည်။ ဆိုလိုသည်မှာ [Psiphon](https://psiphon.ca/) သည် အလုပ် လုပ်သင့်သည်။ + စတင်အလုပ်လုပ်သည့် အချိန် + %1$s စက္ကန့် + ပိတ်ဆို့ခံရဖွယ် ရှိသည် + အလုပ်လုပ်နေသည် + [Tor](https://www.torproject.org/) ကို ပိတ်ဆို့ထားပုံ ရသည်။ + ကျွန်ုပ်တို့သည် နဂိုမူလ Tor bridges နှင့်/ သို့မဟုတ် Tor directory authorities ကို အောင်မြင်စွာ ချိတ်ဆက်နိုင်ခဲ့သည်။ ဆိုလိုသည်မှာ [Tor](https://www.torproject.org/) သည် သုံး၍ ရသင့်သည်။ + နဂိုမူလ Bridge များ + %1$s/%2$s အိုကေ + လုပ်ပိုင်ခွင့်ရှိသူများ လမ်းညွှန် + %1$s/%2$s အိုကေ + အမည် + လိပ်စာ + အမျိုးအစား + ချိတ်ဆက်မည် + ဒေတာဖလှယ်ခြင်း\n + ပိတ်ဆို့ခံရဖွယ် ရှိသည် + အလုပ်လုပ်နေသည် + [RiseupVPN](https://riseup.net/vpn) ကို ပိတ်ဆို့ထားပုံ ရသည်။ + ကျွန်ုပ်တို့အနေဖြင့် RiseupVPN\ ၏ bootstrap ဆာဗာနှင့် VPN gateways များကို အောင်မြင်စွာ ချိတ်ဆက်နိုင်ခဲ့သည်။ ဆိုလိုသည်မှာ [RiseupVPN](https://riseup.net/vpn) ကို သုံး၍ ရသင့်ပါသည်။ + Bootstrap ဆာဗာ + OpenVPN ချိတ်ဆက်မှုများ + ပေါင်းစပ် ချိတ်ဆက်မှုများ + ပိတ်ဆို့ထားသည် + %1$s ပိတ်ဆို့ထားသည် + %1$s ပိတ်ဆို့ထားသည် + အိုကေ + ဤစမ်းသပ်မှုသည် အစမ်းသဘော ဖြစ်သည်။ + သတင်း + သတင်း + အိုကေ + ဖျက်သိမ်းရန်​ + ထပ်မမေးပါနှင့် + ဖျက်မည် + ပြဿနာ + ထပ်ကြိုးစားပါ + ကောင်းပါပြီ + ရပါတယ်၊ ကျေးဇူးပါ + ယခု မဟုတ်ပါ + ဘာဖြစ်ဖြစ် စမ်းမည် + VPN ကို ပိတ်မည် + အမြဲတမ်း စမ်းမည် + စမ်းသပ်မှုကို မလုပ်ဆောင်နိုင်ပါ။ သင့် အင်တာနက် ချိတ်ဆက်မှုကို စစ်ဆေးပါ။\n + URL စာရင်းကို ဒေါင်းလုဒ်လုပ်၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။ + ကျေးဇူးပြု၍ စမ်းသပ်မှုအသစ် မစတင်မီ လက်ရှိလုပ်ဆောင်နေသော စမ်းသပ်မှုများ ပြီးဆုံးရန် စောင့်ပါ။ + အသိပေးချက်ဆိုင်ရာ ခွင့်ပြုချက်များ လိုအပ်သည်။ ကျေးဇူးပြု၍ သင့်ဖုန်း၏ ဆက်တင်များထဲတွင် ၎င်းတို့ကိုဖွင့်ပြီး သင်၏ OONI Probe အက်ပ်တွင် ၎င်းတို့ကို ဖွင့်ပါ။ + ဆက်တင်များသို့ သွားမည် + စမ်းသပ်မှုတစ်ခု လုပ်ဆောင်နေချိန်တွင် ဤမျက်နှာပြင်ကို ပိတ်ထားသည်။ + တိုင်းတာမှု ဒေတာအကြမ်းကို ဒေါင်းလုဒ်လုပ်ရန် သင်သည် အင်တာနက်နှင့် ချိတ်ဆက်ထားရန် လိုအပ်သည်။ + ရလဒ်များကို အပ်လုဒ်လုပ်ခြင်း မရှိပါ + သင့်စမ်းသပ်မှု ရလဒ်အချို့ကို OONI ဆာဗာများသို့ အပ်လုဒ် လုပ်ခြင်း မရှိသေးပါ။ OONI ၏ ဒေတာအစုသို့ ထည့်ပေးလိုပါက ၎င်းတို့ကို အပ်လုဒ် လုပ်ပါ။ + အပ်လုဒ် + %1$s ကို အပ်လုဒ်လုပ်နေသည်... + ဘက်ထရီ ပိုမိုကောင်းမွန်အောင် လုပ်ဆောင်ခြင်းမရှိဘဲ OONI Probe သည် စမ်းသပ်မှုအား အလိုအလျောက် မလည်ပတ်နိုင်ပါ။ ထပ်မံ ကြိုးစားလိုပါသလား။ + သင်၏ VPN ချိတ်ဆက်မှုကို ပိတ်ပါ။ + အကယ်၍ သင်သည် VPN ကိုဖွင့်ထားလျက် OONI Probeကို စမ်းသပ်လုပ်ဆောင်ပါက၊ စမ်းသပ်မှုရလဒ်များသည် နိုင်ငံမှားယွင်းကာ ထွက်ပေါ်လာနိုင်သည်။ သင်၏ VPN ချိတ်ဆက်မှုကို ပိတ်ပါ။ + အချို့သော တိုင်းတာမှုများသည် VPN ကို ကျော်၍ လုပ်ဆောင်ခဲ့သည်။ + VPN ကို ဖွင့်ထားလျက် တိုင်းတာမှုများအား အပ်လုဒ်လုပ်ပါက၊ စမ်းသပ်မှု ရလဒ်များသည် နိုင်ငံ မှားယွင်းကာ ထွက်ပေါ်လာနိုင်သည်။ + အပ်လုဒ်လုပ်ခြင်း အောင်မြင်သည် + ပျက်ကွက်မှု မှတ်တမ်းကို ပြသရန်\n + အင်တာနက် ဆင်ဆာဖြတ်ခြင်းဆိုင်ရာ အပ်ဒိတ်များကို ရယူပါ။ + အရေးပေါ် ဆင်ဆာဖြတ်တောက်မှု ဖြစ်ရပ်များအတွင်း OONI Probe စမ်းသပ်မှုများကို လုပ်ဆောင်ရန် စိတ်ဝင်စားပါသလား။ သင့် အနီးရှိ အင်တာနက် ဆင်ဆာ ဖြတ်တောက်မှုကို ကျွန်ုပ်တို့ ကြားရသည့်အခါ အချက်အလက် သတင်း လက်ခံရရှိရန် အသိပေးချက်များကို ဖွင့်ပါ။ + စစ်ဆေးမှုများ၏ တိကျမှုကို မြှင့်တင်ရန်၊ ကျွန်ုပ်တို့သည် GPS ခွင့်ပြုချက်များ လိုအပ်ပါသည်။ OONI သည် သင့် GPS အနေအထား၏ ခန့်မှန်းခြေကိုသာ စုဆောင်း ပါမည်။ + စမ်းသပ်မှုရလဒ်အားလုံးကို ဖျက်လိုပါသလား။ + ဤစမ်းသပ်မှုကို ဖျက်လိုပါသလား။ + ကျေးဇူးပြု၍ အနည်းဆုံး စမ်းသပ်မှုတစ်ခု ဖွင့်ပါ + ဤအကွက်တွင် ကိန်းဂဏန်းများကိုသာ ထည့်သွင်းပါ။ + စမ်းသပ်မှု ပြန်လုပ်ပါ + ဤစမ်းသပ်မှု မအောင်မြင်ပါ။ စမ်းသပ်မှုကို ပြန်လည် လုပ်ဆောင်လိုပါသလား။ + သင်သည် ဝဘ်ဆိုဒ် %1$s ကို ပြန်လည် စမ်းသပ် တော့မည်။ + စမ်းမည် + ဤဝဘ်စာမျက်နှာမှ ထွက်သည့်အခါ သင့် URL များကို သိမ်းဆည်းမည် မဟုတ်ပါ။ ဤစာမျက်နှာမှ ထွက်လိုသည်မှာ သေချာပါသလား။ + Manual Upload ကို ဖွင့်မလား။ + ဤဆက်တင်သည် သင့်အား မထုတ်ဝေရသေးသော တိုင်းတာမှုများကို ကိုယ်တိုင် ပြန်တင်ခွင့် ပြုသည်။ + ဖွင့်မည် + ရပါတယ်၊ ကျေးဇူးပါ + အပ်လုဒ်လုပ်ခြင်း မအောင်မြင်ပါ + ကျွန်ုပ်တို့သည် အတိုင်းအတာများကို %1$s/%2$s အပ်လုဒ်လုပ်၍ မရပါ။ မအောင်မြင်ခြင်း မှတ်တမ်းကို OONI developer များနှင့် မျှဝေထားပါသည်။ + မှတ်တမ်းဖိုင်ကို ရှာမတွေ့ပါ + ဆီလျော်သော URL များ မတွေ့ပါ + JSON မရှိပါ + ဤစမ်းသပ်မှုကို ရပ်လိုပါသလား။ + ဤအချိန်မှစ၍ လက်ရှိစမ်းသပ်မှုကို ရပ်မည် ဖြစ်သည်။ + စမ်းသပ်မှုများကို အလိုအလျောက် လုပ်ဆောင်လိုပါသလား။ + အလိုအလျောက် စမ်းသပ်ခြင်းကို ဖွင့်ခြင်းဖြင့် သင်သည် OONI တိုင်းတာမှုများကို ပုံမှန် ပံ့ပိုးပေးမည် ဖြစ်သည်။ + ကျေးဇူးပြု၍ အက်ပ်အား နောက်တွင် ဖွင့်ခွင့် ပြုပါ။ + ငါ့ကို နောက်မှ သတိပေးပါ + Clipboard ထဲသို့ ကူးမည် + အပ်လုဒ် မလုပ်ပါ + အပ်လုဒ် + အချို့ကို အပ်လုဒ်မလုပ်ခဲ့ပါ + အားလုံးကို အပ်လုဒ်လုပ်ပါ + ဝဘ်ဆိုဒ်များ + ချက်ခြင်း မက်ဆေ့ချ် + Middleboxes + စွမ်းဆောင်ရည် + ဆင်ဆာရှောင်တိမ်းခြင်း + စမ်းသပ် လေ့လာနေဆဲ + HTTP မဆီလျော်သော တောင်းဆိုမှုလိုင်း စမ်းသပ်မှု + HTTP Header Field Manipulation စမ်းသပ်မှု + ချိတ်ဆက်နိုင်စွမ်း စမ်းသပ်မှု + NDT မြန်နှုန်းစမ်းသပ်မှု + DASH ထုတ်လွှင့် စမ်းသပ်မှု + WhatsApp စမ်းသပ်မှု + Telegram စမ်းသပ်မှု + Facebook Messenger စမ်းသပ်မှု + Psiphon စမ်းသပ်မှု + Tor စမ်းသပ်မှု + RiseupVPN စမ်းသပ်မှု + Signal စမ်းသပ်မှု + ဆက်တင်များ + စမ်းသပ်မှု ကာလအတွက် သင် သတ်မှတ်ထားသော အချိန်ပမာဏသည် အလွန် နည်းသည်။ + OONI အကြောင်း + Open Observatory of Network Interference (OONI) သည် Tor ပရောဂျက် အောက်ရှိ လွတ်လပ်ဆော့ဖ်ဝဲလ် ပရောဂျက်တစ်ခု ဖြစ်ပြီး ကမ္ဘာတစ်ဝှမ်းရှိ အင်တာနက် ဆင်ဆာဖြတ်တောက်မှုများကို ပွင့်လင်းမြင်သာမှု ရှိစေရန် ရည်ရွယ်ပါသည်။ \n\n၂၀၁၂ ခုနှစ်မှ စတင်၍ OONI ၏ ကမ္ဘာ့ အသိုင်းအဝိုင်းသည် နိုင်ငံပေါင်း ၂၀၀ ကျော်တွင် ကွန်ရက်များကို တိုင်းတာနေပါသည်။ ဤတိုင်းတာမှုအချို့သည် အင်တာနက် ဆင်ဆာ ဖြတ်တောက်ခြင်း၏ သက်သေအဖြစ် တည်ရှိနေသည်။ + ပိုမိုလေ့လာရန် + ဘလော့ဂ် + အစီရင်ခံစာများ + OONI ဒေတာမူဝါဒ + အသိပေးချက်များ + ဖွင့်ထားသည် + စမ်းသပ်မှု ပြီးပါက အသိပေးမည် + သတင်းအသစ် ရယူရန် + အလိုအလျောက် စမ်းသပ်ခြင်း + စမ်းသပ်မှုများကို အလိုအလျောက် လုပ်ဆောင်ပါ + အလိုအလျောက်စမ်းသပ်မှု အရေအတွက် - %1$s။ + နောက်ဆုံး လုပ်ဆောင်ခဲ့သည့် အလိုအလျောက် စမ်းသပ်မှု - %1$s။ + WiFi နှင့် သာ + အားသွင်းနေစဉ်သာ + အလိုအလျောက် စမ်းသပ်ခြင်းကို ဖွင့်ထားခြင်းဖြင့် OONI Probe စမ်းသပ်မှုများသည် တစ်နေ့လျှင် အကြိမ်များစွာ အလိုအလျောက် လုပ်ဆောင်မည် ဖြစ်သည်။ သင်၏ စမ်းသပ်မှုရလဒ်များကို OONI Explorer တွင် အလိုအလျောက် ထုတ်ပြန်လိမ့်မည် - https://explorer.ooni.org/ \n\nအရေးကြီးသည် - သင့်စက်တွင် VPN ဖွင့်ထားပါက OONI Probe သည် စမ်းသပ်မှုများကို အလိုအလျောက် လုပ်ဆောင်မည် မဟုတ်ပါ။ အလိုအလျောက် OONI Probe စမ်းသပ်မှုအတွက် သင့်စက် VPN ကို ပိတ်ပါ။ ပိုမိုလေ့လာရန် - https://ooni.org/support/faq/#can-i-run-ooni-probe-over-a-vpn သို့ သွားပါ + မျှဝေခြင်း + အလိုအလျောက် ထုတ်ပြန်သော ရလဒ်များ + လူကိုယ်တိုင် ရလဒ် အပ်လုဒ်လုပ်ရန် + ကွန်ရက် အချက်အလက် ထည့်သွင်းရန် + ခန့်မှန်း geo-location ထည့်သွင်းရန် + ကျွန်ုပ်၏ IP လိပ်စာ ထည့်သွင်းရန် + နိုင်ငံကုဒ် ထည့်သွင်းရန် + တိုင်းတာမှုများကို မည်သည့်နိုင်ငံမှ ကောက်ယူနေကြောင်း သိရှိရန် ဤ သတင်းအချက်အလက် (ဥပမာ - အီတလီနိုင်ငံ အတွက် အတိုက်ကောက်စာလုံး IT) လိုအပ်သည်။ ဤရွေးချယ်မှုကို ပိတ်လိုသည်မှာ သေချာသလား။ + ရလဒ်များကို ထုတ်ပြန်ခြင်းဖြင့် သင်သည် ကွန်ရက်အား နှောင့်ယှက်မှုဆိုင်ရာ ပွင့်လင်းမြင်သာမှုကို တိုးမြင့်စေလျက် OONI အသိုင်းအဝိုင်းအား ကူညီပေးသည်။\n\nအင်တာနက်ဝန်ဆောင်မှုပေးသူများအား ခွဲခြားသတ်မှတ်ရန်အတွက် ကွန်ရက်သတင်းအချက်အလက်များ (ဥပမာ - အလိုအလျောက်စနစ် နံပါတ်) လိုအပ်ပါသည်။ + စမ်းသပ်ရွေးချယ်မှုများ + အထက်ဖော်ပြပါ စမ်းသပ်မှု ဆက်တင်များမှတစ်ဆင့် သင် ပြင်ဆင်သတ်မှတ်ထားသည့် အရာ (ဥပမာ - WhatsApp စစ်ဆေးမှုအား ပိတ်ခြင်း) သည် စမ်းသပ်မှုများကို ကိုယ်တိုင် လုပ်ဆောင်သည့် အပြင် စမ်းသပ်မှုများကို အလိုအလျောက် လည်ပတ်စေသည် (အလိုအလျောက် စမ်းသပ်မှုကို ဖွင့်ထားသောအခါ) တွင် သက်ရောက်မည် ဖြစ်သည်။ + တာရှည်စမ်းသပ်မှု + ရှေ့ဘက်တွင် အချိန်ကြာမြင့်သော စမ်းသပ်မှုများကို လုပ်ဆောင်မလား။ + ကိုယ်ရေးလုံခြုံမှု + ပျက်စီးမှု အစီရင်ခံစာများ ပေးပို့မည် + အဆင့်မြင့် + အမှောင်မုဒ် + အမှားပြင်ဆင်မှု မှတ်တမ်းများ\n + လတ်တလော မှတ်တမ်းများကို ကြည့်ပါ + ဘာသာစကား ဆက်တင် + ဘာသာစကား ရွေးမည်\n + domain fronting နည်းကို အမြဲသုံးရန်\n + OONI နောက်ခံ ပရောက်စီ + ကြားခံ အင်တာနက်စနစ် + မရှိ + Psiphon + အထူး ပရောက်စီ\n + အထူး ပရောက်စီ URL + အထူး ပရောက်စီ ပရိုတိုကော\n + ချိတ်ဆက်မှု + အထိုင်နေရာ အမည် + ပေါ့တ် + အထောက်အထားများ (မထည့်လည်းရသည်) + အသုံးပြုသူအမည် + စကားဝှက် + ဖန်တီးပြုပြင်သော ပရောက်စီပေါ်တွင် Psiphon ကိုသုံးပါ + OONI Probe ကို အသုံးပြု၍ မရနိုင်လျှင် ဖြစ်နိုင်ချေရှိသော ပိတ်ဆို့မှုကို ကျော်ဖြတ်နိုင်ရန် [Psiphon](https://psiphon.ca/) ကို ဖွင့်ပါ။ တနည်းအားဖြင့် သင်သည် စိတ်ကြိုက် ပရောက်စီကို သုံးနိုင်သည်။ + စမ်းသပ်ကာလကို ကန့်သတ်မည် + စမ်းသပ်မှုကာလ + စမ်းသပ်ရန် ဝဘ်ဆိုဒ် အမျိုးအစားများ + အမျိုးအစား %1$s ကို ဖွင့်ထားသည် + တည်းဖြတ်မည် + အားလုံးကို မရွေးချယ်ရန်\n + အားလုံးကို ရွေးချယ်မည်\n + သိမ်းမည်\n + မသိမ်းဆည်းရသေးသော အပြောင်းအလဲများ + သင် ဖွင့်ထားသော အမျိုးအစားများအတွက် အပြောင်းအလဲအချို့ ပြုလုပ်ထားသည်။ ၎င်းတို့ကို သင် သိမ်းဆည်းလိုသလား။ + သိမ်းမည်\n + ဖယ်ရှားမည်\n + စမ်းသပ်မည့် ဝဘ်ဆိုဒ်များ ရွေးချယ်ရန် + URL + URL များ ထည့်ထားခြင်း မရှိပါ + စမ်းမည်\n + ဝဘ်ဆိုဒ်ထည့်ရန် + တန်းပလိတ်မှ တင်ရန် + စမ်းသပ်ထားသော ဝဘ်ဆိုဒ်အရေအတွက် (0 သည် ၀က်ဘ်ဆိုဒ်အားလုံးကို ဆိုလိုသည်) + WhatsApp ကို စမ်းသပ်မည်\n + Telegram ကို စမ်းသပ်မည်\n + Facebook Messenger ကို စမ်းသပ်မည်\n + Signal ကို စမ်းသပ်မည်\n + HTTP မဆီလျော်သော တောင်းဆိုမှု လိုင်းစမ်းသပ်မှုကို လုပ်ဆောင်ရန် + HTTP Header Field Manipulation စမ်းသပ်မှုကို လုပ်ဆောင်မည် + NDT မြန်နှုန်း စမ်းသပ်မှုကို လုပ်ဆောင်မည် + အလိုအလျောက် NDT ဆာဗာ ရွေးချယ်မှု + NDT ဆာဗာ လိပ်စာ + NDT ဆာဗာ ပေါ့တ် + DASH Streaming စမ်းသပ်မှုကို လုပ်ဆောင်ရန် + အလိုအလျောက် DASH ဆာဗာ ရွေးချယ်မှု + DASH ဆာဗာ + DASH ဆာဗာပေါ့တ် + Psiphon ကို စမ်းသပ်မည်\n + Tor ကို စမ်းသပ်မည်\n + RiseupVPN ကို စမ်းသပ်မည်\n + VPN အသုံးပြုနေချိန်တွင် သတိပေးပါ + ပံ့ပိုးကူညီရန် အီးမေးလ် ပို့ပါ + သင်ကြုံတွေ့နေရသော ပြဿနာကို ကျေးဇူးပြု၍ ဖော်ပြပါ - + အက်ပ်နှင့် iOS ဗားရှင်း အချက်အလက်များဖြင့် bugs@openobservatory.org သို့ အီးမေးလ် ပို့ပါ။ အောက်တွင်ပါရှိသော \"Clipboard ထဲသို့ ကူးမည်\" ကို နှိပ်၍ ကျွန်ုပ်တို့ အီးမေးလ်လိပ်စာကို ကူးပါ။ + လက်ရှိ အက်ပ် ဘာသာစကားသည် %1$s ဖြစ်သည် + ဘာသာစကား + သိုလှောင်မှုအား အသုံးပြုမှု + အသုံးပြုထားသော သိုလှောင်မှု + ဖျက်မည် + ရှင်းမည် + သင့်စက်မှ OONI တိုင်းတာမှုအားလုံးကို သင် ဖျက်တော့မည်။ အချက်အလက်များကို အပ်လုဒ် လုပ်ထားလျှင် ၎င်းတို့ကို [OONI Explorer](https://explorer.ooni.org) တွင် ဆက်လက် ရရှိနိုင်သည်။ + ပြီးသွားပါပြီ + စမ်းသပ်မှုကို ရပ်ပါ + mirror လုပ်ကြည့်ရန် + တင်နေပါသည်... + မမျှော်လင့်ထားသော ပြဿနာ ဖြစ်ပေါ်ခဲ့သည်။ ဤစာမျက်နှာကို ပြန်လည်စတင်ပါ။ + သင်သည် OONI Probe စမ်းသပ်မှု တစ်ခုကို လုပ်ဆောင်ပါတော့မည်။ + %1$s URL များ + စမ်းသပ်မှု အမည် + စမ်းသပ်မှု အသေးစိတ် + စမ်းမည် + နောက်ဆုံးပေါ် မဟုတ် + ဤစမ်းသပ်မှု လုပ်ဆောင်ရန် OONI Probe ဗားရှင်းအသစ် လိုသည်။ + အပ်ဒိတ်လုပ်မည် + ပိတ်မည် + မဆီလျော်သော ကန့်သတ်ချက်ဘောင် + OONI Run လင့်ခ်သည် ပုံပျက်နေသည် သို့မဟုတ် သင့်အက်ပ်သည် ခေတ်မမီတော့ပါ။ + သင်သည် ဝဘ်ဆိုဒ်များထဲမှ ကျပန်းနမူနာဝဘ်ဆိုဒ်တခုကို စမ်းသပ်မည်။ + OONI Run လင့်ခ်ကို မနှိပ်မီ စမ်းသပ်မှု အပြီးသတ်ရန် စောင့်ပါ။ + မူးယစ်ဆေးဝါးနှင့် အရက် + ဘာသာတရား + ညစ်ညမ်းရုပ်ပုံ + ဆွဲဆောင်မှုရှိသော ဝတ်စားဆင်ယင်မှု + နိုင်ငံရေး ဝေဖန်မှု + လူ့အခွင့်အရေး ကိစ္စများ + ပတ်ဝန်းကျင် + အကြမ်းဖက်ဝါဒနှင့် စစ်သွေးကြွများ + အမုန်းစကား + သတင်းမီဒီယာ + လိင်ကိစ္စ ပညာပေး\n + ပြည်သူ့ကျန်းမာရေး + လောင်းကစားခြင်း + အင်တာနက်ဆင်ဆာ ရှောင်တိမ်းသည့် ကိရိယာများ + အွန်လိုင်း ချိန်းတွေ့ခြင်း + လူမှုကွန်ရက် + LGBTQ+ + File-sharing + ဟက်ကင်းကိရိယာများ + ဆက်သွယ်ရေးကိရိယာများ + မီဒီယာ ဝေမျှခြင်း + နေရာအထိုင်ချခြင်း နှင့် ဘလော့ဂ်တွင် စာရေးသားခြင်း + ရှာဖွေရေးအင်ဂျင်များ + ဂိမ်းဆော့ခြင်း + ယဉ်ကျေးမှု + ဘောဂဗေဒ + အစိုးရ + အီလက်ထရောနစ် ကူးသန်းရောင်းဝယ်ရေး + အကြောင်းအရာကို ထိန်းချုပ်မည် + အစိုးရ အဖွဲ့အစည်းများ + အထွေထွေ အကြောင်းအရာ + မူးယစ်ဆေးဝါးနှင့် အရက်သောစာ သုံးစွဲ၊ ရောင်းချခြင်း + ပံ့ပိုးကူညီမှုနှင့် ဝေဖန်ထောက်ပြမှု အပါအဝင် ဘာသာရေးဆိုင်ရာ ကိစ္စများ + ကြည်လင်ပြတ်သားသော ညစ်ညမ်းရုပ်ပုံများ နှင့် ကြည်လင်ပြတ်သားစွာ မဖော်ပြထားသော ညစ်ညမ်းရုပ်ပုံများ + အဝတ်အစား အနည်းငယ်သာ ဝတ်ဆင်ထားသော အမျိုးသမီးများ၏ ဆွဲဆောင်မှုရှိသော ဝတ်စားဆင်ယင်မှုနှင့် သရုပ်ဖော်ပုံ + ဝေဖန်ထောက်ပြစရာ နိုင်ငံရေးအမြင်များ + လူ့အခွင့်အရေးကိစ္စများ + သဘာဝ ပတ်ဝန်းကျင်ဆိုင်ရာ ကိစ္စရပ်များအပေါ် ဆွေးနွေးချက်များ + အကြမ်းဖက်ဝါဒ၊ အကြမ်းဖက် စစ်သွေးကြွ သို့မဟုတ် ခွဲထွက်ရေး လှုပ်ရှားမှုများ + လူမျိုး၊ လိင်၊ လိင်စိတ် သို့မဟုတ် အခြားသော ဝိသေသ လက္ခဏာများအပေါ် အခြေခံ၍ သီးခြားအုပ်စုများကို နှိမ့်ချခြင်း + အဓိက သတင်းဝဘ်ဆိုဒ်များ၊ ဒေသဆိုင်ရာ သတင်းများနှင့် လွတ်လပ်သော မီဒီယာများ + သန္ဓေတားဆေး၊ STDs၊ မုဒိမ်းမှု ကာကွယ်ရေးနှင့် ကိုယ်ဝန်ဖျက်ချခြင်း အပါအဝင် လိင်ပိုင်းဆိုင်ရာ ကျန်းမာရေး ကိစ္စများ + COVID-19၊ HIV/AIDS၊ Ebola ကဲ့သို့သော ပြည်သူ့ကျန်းမာရေး ပြဿနာများ + အွန်လိုင်းလောင်းကစားနှင့် အလောင်းအစား + အမည်ဝှက်ထားခြင်း၊ ဆင်ဆာဖြတ်တောက်ခြင်း ရှောင်တိမ်းခြင်းနှင့် ကုဒ်ဝှက်ခြင်း + အွန်လိုင်းချိန်းတွေ့ ဆိုဒ်များ + အွန်လိုင်း လူမှုကွန်ရက် ကိရိယာများနှင့် ပလက်ဖောင်းများ + (ညစ်ညမ်းရုပ်ပုံစာပေ မပါဝင်ဘဲ) သက်ဆိုင်ရာ ကိစ္စများကို ဆွေးနွေးသည့် LGBTQ+ အသိုင်းအဝိုင်း + cloud-based ဖိုင်သိုလှောင်မှု၊ torrents နှင့် P2P အပါအဝင် ဖိုင်မျှဝေခြင်း\n + ကွန်ပျူတာ လုံခြုံရေး ကိရိယာများနှင့် သတင်းများ + VoIP၊ စာတို ပေးပို့ခြင်းနှင့် ဝဘ်မေးလ် အပါအဝင် တစ်ဦးချင်းနှင့် အဖွဲ့လိုက် ဆက်သွယ်ရေး ကိရိယာများ + ဗီဒီယို၊ အသံနှင့် ဓာတ်ပုံ မျှဝေခြင်း + ဝဘ်ဆိုဒ် အထိုင်နေရာ၊ ဘလော့ဂ်ရေးသားခြင်း နှင့် အခြား အွန်လိုင်းထုတ်ဝေမှု + ရှာဖွေရေးအင်ဂျင်များနှင့် ပေါ်တယ်လ်များ + အွန်လိုင်း ဂိမ်းများနှင့် ဂိမ်းပလက်ဖောင်းများ (လောင်းကစားဆိုဒ်များ မပါ)\n + သမိုင်း၊ စာပေ၊ ဂီတ၊ ရုပ်ရှင်၊ သရော်စာနှင့် ဟာသများ အပါအဝင် ဖျော်ဖြေမှု\n + အထွေထွေ စီးပွားရေးဖွံ့ဖြိုးတိုးတက်မှုနှင့် ဆင်းရဲမွဲတေမှု + စစ်တပ်အပါအဝင် အစိုးရပိုင် ဝက်ဘ်ဆိုက်များ + စီးပွားဖြစ် ဝန်ဆောင်မှုများနှင့် ထုတ်ကုန်များ + ထိန်းချုပ်ရန် အသုံးပြုသည့် နူးညံ့သိမ်မွေ့သော သို့မဟုတ် အပြစ်ကင်းသော အကြောင်းအရာ + ကုလသမဂ္ဂ အပါအဝင် အစိုးရ အဖွဲ့အစည်းများ + အမျိုးအစား မခွဲခြားရသေးသော ဆိုဒ်များ + diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml new file mode 100644 index 000000000..5c2d54de9 --- /dev/null +++ b/app/src/main/res/values-vi/strings.xml @@ -0,0 +1,533 @@ + + + ONNI Probe + OONI Probe là gì? + Ứng dụng này để đo lường kiểm duyệt internet\n\nCác trang web và các ứng dụng mạng xã hội có bị chặn không? Kết nối internet của bạn có bị chậm bất thường không?\n\nHãy chạy ứng dụng OONI Probe để tìm hiểu! + Tôi đã hiểu + Chú ý! + Dữ liệu của OONI được công bố công khai, bao gồm thông tin về mạng của bạn. + Bất cứ ai giám sát hoạt động internet của bạn (ví dụ như chính phủ hay nhà mạng) sẽ biết bạn đang chạy OONI Probe. + Bạn có thể kiểm tra các trang web bị chặn (hoặc chọn trang bất kì để kiểm tra) + Tôi đã hiểu + Tìm hiểu thêm + Pop Quiz + Đúng + Sai + Quay lại + Tiếp tục + Câu hỏi 1/2 + Nếu có ai đó đang giám sát hoạt động internet của tôi, họ sẽ có thể biết tôi đang chạy ứng dụng OONI Probe. + Cảnh báo + ONNI Probe không phải công cụ có tính bảo mật cá nhân. Bất cứ ai đang giám sát hoạt động internet của bạn sẽ biết được bạn đang chạy những phần mềm nào. + Câu hỏi 2/2 + Bất cứ khi nào tôi chạy ứng dụng OONI Probe, dữ liệu mạng mà tôi thu thập được sẽ được tự động công bố. + Cảnh báo + Để tăng tính minh bạch của việc kiểm duyệt internet, dữ liệu mạng của tất cả người dùng OONI Probe sẽ tự động được công bố (trừ khi họ tắt tính năng này khi cài đặt). + Kiểm tra tự động + Để đo lường sự kiểm duyệt internet hàng ngày, vui lòng bật chế độ kiểm tra tự động để OONI Probe có thể chạy các bài kiểm tra định kỳ\n\nĐừng lo, chúng tôi sẽ lưu ý đến việc sử dụng pin.\n\nBạn có thể tắt kiểm tra tự động ở phần cài đặt bất cứ lúc nào. + Báo cáo sự cố + Để cải thiện OONI Probe, chúng tôi muốn thu thập các báo cáo sự cố ẩn danh khi ứng dụng không hoạt động bình thường.\n\nBạn có muốn chọn gửi báo cáo sự cố cho nhóm phát triển OONI không? + + Không + Cài đặt mặc định + Chúng tôi thu thập và công bố: + Mã quốc gia (ví dụ IT đại diện cho Italy) + Thông tin mạng (bao gồm Số hệ thống tự trị - ASN) + Thời gian và ngày kiểm tra + Chúng tôi luôn cố gắng để không công bố địa chỉ IP của bạn hay bất kỳ thông tin tiềm tàng nào khác nhằm nhận dạng cá nhân.\n\nTìm hiểu thêm thông qua [Chính sách dữ liệu của OONI] (https://ooni.org/about/data-policy/). + Bằng việc nhấn \"OK\", bạn sẽ chia sẻ báo cáo sự cố để giúp chúng tôi cải thiện OONI Probe. + Bắt đầu + Thay đổi mặc định + Bảng tóm tắt + Chạy + N/A + Chạy + Lần kiểm tra gần đây nhất + Ước lượng: + Chọn trang web + Đang chạy: + Ước lượng thời gian còn lại: + %1$s giây + Chuẩn bị kiểm tra + Tính toán ETA + Hiển thị Nhật ký + Đóng Nhật ký + Đang dừng kiểm tra + Đang hoàn tất các bài kiểm tra dở dang, vui lòng chờ đợi.... + Proxy đang sử dụng + Chạm vào thẻ để biết thêm chi tiết + ~%1$s + Kiểm tra việc chặn các trang web + Kiểm tra xem các trang web có bị chặn không bằng cách sử dụng [Kiểm tra Web Connectivity] của OONI (https://ooni.org/nettest/web-connectivity/).\n\nMỗi khi nhấn Chạy, bạn sẽ kiểm tra các trang web khác nhau từ danh sách [toàn cầu] của Citizen Lab (https://github.com/citizenlab/test-lists/blob/master/lists/global.csv) và danh sách [quốc gia cụ thể] (https://github.com/citizenlab/test-lists/tree/master/lists).\n\nĐể chọn trang web bất kì và kiểm tra, hãy nhấn vào nút Chọn trang web hoặc chọn các danh mục trang web ở phần cài đặt.\n\nKiểm tra này cho biết các trang web có bị chặn bởi các phương thức giả mạo DNS, chặn TCP/IP hay bởi một proxy HTTP minh bạch không.\n\nKết quả của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). + Kiểm tra xem các trang web có bị chặn không bằng cách sử dụng [Kiểm tra Web Connectivity] của OONI (https://ooni.org/nettest/web-connectivity/).\n\nBạn sẽ kiểm tra các trang web khác nhau từ danh sách [toàn cầu] của Citizen Lab (https://github.com/citizenlab/test-lists/blob/master/lists/global.csv) và danh sách [quốc gia cụ thể] (https://github.com/citizenlab/test-lists/tree/master/lists).\n\nKiểm tra này cho biết các trang web có bị chặn bởi các phương thức giả mạo DNS, chặn TCP / IP hay bởi một proxy HTTP minh bạch hay không.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). + Kiểm tra tốc độ và hiệu suất mạng của bạn + Đo tốc độ và hiệu suất mạng của bạn bằng cách sử dụng kiểm tra [NDT] (https://ooni.org/nettest/ndt/).\n\nĐo hiệu suất phát trực tuyến video bằng bài kiểm tra [DASH] (https://ooni.org/nettest/dash/).\n\nCác bài kiểm tra này sử dụng dữ liệu tùy thuộc vào tốc độ mạng của bạn.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/).\n\nTuyên bố miễn trừ trách nhiệm: Những kiểm tra này dựa trên máy chủ của bên thứ ba. Do đó, chúng tôi không thể đảm bảo rằng địa chỉ IP của bạn sẽ không bị thu thập. + Bằng cách chạy các bài kiểm tra này, bạn sẽ:\n\n- Đo tốc độ và hiệu suất mạng của bạn (kiểm tra [NDT] (https://ooni.org/nettest/ndt/))\n- Đo hiệu suất phát trực tuyến video (kiểm tra [DASH] (https://ooni.org/nettest/dash/))\n- Kiểm tra sự hiện diện của [công nghệ middlebox] (https://ooni.org/support/glossary/#middlebox) trên mạng của bạn qua các kiểm tra ([HTTP Invalid Request Line] (https://ooni.org/nettest/http-invalid -request-line /) và [HTTP Header Field Manipulation] (https://ooni.org/nettest/http-header-field-manipulation/) )\n\nCác bài kiểm tra này sử dụng dữ liệu tùy thuộc vào tốc độ mạng của bạn.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/) và [OONI API] (https://api.ooni.io/).\n\n** Tuyên bố miễn trừ trách nhiệm: ** Các bài kiểm tra [NDT] (https://ooni.org/nettest/ndt/) và [DASH] (https://ooni.org/nettest/dash/) được thực hiện trên các máy chủ của bên thứ ba được cung cấp bởi [Measurement Lab (M-Lab)] (https://www.measurementlab.net/). Nếu bạn chạy các bài kiểm tra này, M-Lab sẽ thu thập và công bố địa chỉ IP của bạn (cho mục đích nghiên cứu), cho dù cài đặt OONI Probe của bạn như thế nào. Tìm hiểu thêm về quản trị dữ liệu của M-Lab thông qua [tuyên bố về quyền riêng tư] (https://www.measurementlab.net/privacy/). + Phát hiện các middlebox trong mạng của bạn + Nhà mạng thường sử dụng các thiết bị mạng (middlebox) cho các mục đích mạng khác nhau (ví dụ như bộ nhớ đệm). Đôi khi những middlebox này được sử dụng để thực hiện kiểm duyệt và/ hoặc giám sát internet.\n\nTìm các middlebox trong mạng của bạn bằng cách kiểm tra [HTTP Invalid Request Line] của OONI (https://ooni.org/nettest/http-invalid-request-line/) và kiểm tra [HTTP Header Field Manipulation] (https://ooni.org/nettest/http-header-field-manipulation/) .\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). + Kiểm tra việc chặn các ứng dụng nhắn tin tức thời + Kiểm tra [WhatsApp] (https://ooni.org/nettest/whatsapp/), [Facebook Messenger] (https://ooni.org/nettest/facebook-messenger/), [Telegram] (https://ooni .org/nettest/telegram/) và [Signal] (https://ooni.org/nettest/signal) có bị chặn không.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). + Kiểm tra việc chặn các công cụ vượt kiểm duyệt + Kiểm tra [Psiphon] (https://ooni.org/nettest/psiphon/), [Tor] (https://ooni.org/nettest/tor/) hay [RiseupVPN] (https://ooni.org/nettest/roseupvpn/) có bị chặn không.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/) và [OONI API] (https://api.ooni.io/). + Chạy các bài kiểm tra thử nghiệm mới + Chạy các bài kiểm tra thử nghiệm mới sau đây do nhóm OONI phát triển:\n%1$s\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/) và [OONI API] (https://api.ooni.io/). + Các bài kiểm tra sau đây sẽ chỉ được chạy khi thực hiện kiểm tra tự động: + Disabled Tests + Gbit/giây + Mbit/giây + kbit/giây + mili giây + Không có sẵn + Không có thông tin + Kết quả kiểm tra + Kết quả kiểm tra + Các bài kiểm tra + Mạng + Sử dụng dữ liệu + Kiểm tra bộ lọc + Tất cả các bài kiểm tra + Trang web + Các middlebox + Hiệu suất + Nhắn tin tức thời + Vượt qua kiểm duyệt Internet + Thử nghiệm + Chưa có bài kiểm tra nào được chạy. Hãy chạy thử 1 bài kiểm tra! + %1$s đã bị chặn + %1$s đã bị chặn + %1$s đã được kiểm tra + %1$s đã được kiểm tra + Đã phát hiện + Chưa phát hiện + Thất bại + %1$s đã bị chặn + %1$s đã bị chặn + %1$s có thể truy cập + %1$s có thể truy cập + %1$s đã bị chặn + %1$s đã bị chặn + %1$s có sẵn + %1$s có sẵn + Kết quả chưa hoàn thiện + Lỗi + Lỗi trong quá trình đo lường + Kết quả không được tải lên + Ngày & Thời gian + Mạng + Quốc gia + Sử dụng dữ liệu + Tổng thời gian chạy + WiFi + Dữ liệu di động + Không có internet + Thất bại + Đã kiểm tra + Đã kiểm tra + Đã khóa + Đã khóa + Trang web + Trang web + Có thể truy cập + Có thể truy cập + Video + Chất lượng + Tải lên + Tải về + Ping + Đã phát hiện + Chưa phát hiện + Thất bại + Đã kiểm tra + Đã kiểm tra + Đã khóa + Đã khóa + Có thể truy cập + Có thể truy cập + Ứng dụng + Các ứng dụng + Đã kiểm tra + Đã kiểm tra + Đã khóa + Đã khóa + Đang hoạt động + Đang hoạt động + Công cụ + Công cụ + Thời gian chạy + Phương pháp + Xem Nhật ký + Dữ liệu + Sao chép URL của Explorer + Chia sẻ URL của Explorer + Sao chép vào Clipboard + Hiển thị trong OONI Explorer + Thất bại + Bạn có thể thử chạy lại bài kiểm tra này + Thử lại + Tìm hiểu cách hoạt động của bài kiểm tra này [tại đây] (%1$s). + Có thể truy cập + %1$s có thể truy cập được + Có khả năng đã bị chặn + %1$s có thể bị chặn bởi %2$s.\n\nLưu ý: Có thể xảy ra hiện tượng dương tính giả. Tìm hiểu thêm [tại đây] (https://ooni.org/support/faq/#what-are-false-pososystem) + Vượt kiểm duyệt + Giả mạo DNS + ** Chặn dựa trên TCP/IP ** + ** Chặn HTTP (có thể có một trang chặn) ** + ** Chặn HTTP (yêu cầu HTTP không thành công) ** + Ứng dụng trên điện thoại + OK + Thất bại + Trang web WhatsApp + OK + Thất bại + Đăng ký + OK + Thất bại + Đang hoạt động + Bài kiểm tra này đã kết nối thành công với các endpoint, dịch vụ đăng ký và giao diện web của WhatsApp (web.whatsapp.com). + Có khả năng bị chặn + WhatsApp có thể đã bị chặn. + Ứng dụng trên điện thoại + OK + Thất bại + Trang web Telegram + OK + Thất bại + Đang hoạt động + Bài kiểm tra này đã kết nối thành công với các endpoint và giao diện web của Telegram (web.telegram.org). + Có khả năng bị chặn + Telegram có thể đã bị chặn + Các kết nối TCP + OK + Thất bại + Tra cứu DNS + OK + Thất bại + Đang hoạt động + Bài kiểm tra này đã kết nối thành công với các endpoint của Facebook và xử lý các địa chỉ IP của Facebook. + Có khả năng bị chặn + Facebook Messenger có thể đã bị chặn. + Có khả năng bị chặn + Signal có thể đã bị chặn. + Đang hoạt động + Bài kiểm tra này đã kết nối thành công với các endpoint của Signal. + Không phát hiện middlebox + Không phát hiện bất thường trên mạng khi giao tiếp với máy chủ của chúng tôi. + Giả mạo mạng + Lưu lượng mạng đã bị thao túng khi liên lạc với các máy chủ kiểm soát của chúng tôi.\n\nĐiều này nghĩa là có thể có một middlebox trong mạng của bạn, có thể nhằm kiểm duyệt và/hoặc giám sát. + Không phát hiện middlebox + Không phát hiện bất thường trên mạng khi giao tiếp với máy chủ của chúng tôi. + Giả mạo mạng + Lưu lượng mạng đã bị thao túng khi liên lạc với các máy chủ kiểm soát của chúng tôi.\n\nĐiều này nghĩa là có thể có một middlebox trong mạng của bạn, có thể nhằm để kiểm duyệt và/hoặc giám sát. + Bạn đã gửi + Bạn đã nhận + Tải lên + Tải về + Ping + Máy chủ + Tỷ lệ truyền lại + Xảy ra lỗi + Ping trung bình + Ước lượng Ping tối đa + MSS + Thời gian chờ + Bạn có thể phát trực tiếp lên đến %1$s mà không bị gián đoạn + Trung vị Tốc độ bit + Hoãn phát lại + Có khả năng bị chặn + Đang hoạt động + [Psiphon](https://psiphon.ca/) có thể đã bị chặn. + Chúng tôi đã bootstrap thành công kết nối Psiphon. Điều này có nghĩa là [Psiphon] (https://psiphon.ca/) sẽ hoạt động. + Thời gian Bootstrap + %1$s giây + Có khả năng bị chặn + Đang hoạt động + [Tor](https://www.torproject.org/) có thể đã bị chặn. + Chúng tôi đã kết nối thành công với cầu chuyển tiếp và/hoặc quản lý thư mục mặc định của Tor. Điều này có nghĩa là [Tor] (https://www.torproject.org/) sẽ hoạt động. + Cầu chuyển tiếp mặc định + %1$s/%2$s OK + Quản lý thư mục + %1$s/%2$s OK + Tên + Địa chỉ nhà + Loại + Kết nối + Giao thức bắt tay + Có khả năng đã bị chặn + Đang hoạt động + [RiseupVPN](https://riseup.net/vpn) có thể đã bị chặn. + Chúng tôi đã kết nối thành công với máy chủ bootstrap của RiseupVPN và các cổng VPN. Điều này có nghĩa là [RiseupVPN] (https://riseup.net/vpn) sẽ hoạt động. + Máy chủ Bootstrap + Các kết nối OpenVPN + Các kết nối bắc cầu + Đã khóa + %1$s đã bị chặn + %1$s đã bị chặn + OK + Đây là bài kiểm tra thử nghiệm. + Cung cấp + Cung cấp + OK + Hủy + Không, đừng hỏi lại + Xóa + Lỗi + Thử lại + Ổn đấy + Không, cảm ơn + Không phải bây giờ + Vẫn chạy tiếp + Tắt VPN + Luôn chạy + Không thể chạy bài kiểm tra. Vui lòng kiểm tra lại kết nối internet của bạn. + Không thể tải danh sách URL. Vui lòng thử lại. + Vui lòng đợi các bài kiểm tra đang chạy kết thúc trước khi bắt đầu một bài kiểm tra mới. + Cần cài đặt cho phép thông báo. Vui lòng bật thông báo trong Cài đặt của điện thoại sau đó bật thông báo trong ứng dụng OONI Probe của bạn. + Đến phần Cài đặt + Màn hình bị khóa khi bài kiểm tra đang chạy + Bạn cần kết nối với Internet để tải về các dữ liệu thô về đo lường + Kết quả không được tải lên + Một số kết quả kiểm tra của bạn chưa được tải lên máy chủ OONI. Nếu bạn muốn đóng góp vào bộ dữ liệu của OONI, vui lòng tải chúng lên. + Tải lên + Đang tải lên %1$s ... + OONI Probe không thể chạy tự động nếu không tối ưu hóa pin. Bạn có muốn thử lại không? + Vui lòng tắt kết nối VPN của bạn. + Nếu bạn chạy OONI Probe mà vẫn bật VPN, kết quả kiểm tra có thể đến từ quốc gia khác. Vui lòng tắt kết nối VPN của bạn. + Một số đo lường đã được thực hiện qua VPN. + Nếu bạn tải lên các đo lường được thực hiện khi bật VPN, kết quả kiểm tra có thể đến từ quốc gia khác. + Tải lên thành công + Hiển thị nhật ký lỗi + Nhận thông tin cập nhật về kiểm duyệt internet + Bạn quan tâm đến việc chạy kiểm tra OONI Probe trong các tình huống kiểm duyệt khẩn cấp? Bật thông báo để nhận tin nhắn khi chúng tôi biết có kiểm duyệt internet ở gần bạn. + Để cải thiện độ chính xác của các bài kiểm tra, chúng tôi cần có quyền truy cập GPS. OONI sẽ chỉ thu thập thông tin gần đúng về vị trí GPS của bạn. + Bạn có muốn xóa tất cả các kết quả kiểm tra không? + Bạn có muốn xóa bài kiểm tra này không? + Vui lòng cho phép chạy ít nhất một bài kiểm tra + Vui lòng chỉ điền các chữ số vào trường này. + Chạy lại bài kiểm tra + Bài kiểm tra này không thành công. Chạy lại bài kiểm tra? + Bạn chuẩn bị kiểm tra lại %1$s trang web. + Chạy + URL của bạn sẽ không được lưu khi bạn rời khỏi màn hình này. Bạn có chắc chắn muốn rời khỏi màn hình này không? + Bật tải lên thủ công? + Cài đặt này cho phép bạn tải lên thủ công các kết quả đo lường chưa được công bố. + Cho phép + Không, cảm ơn + Tải lên thất bại + Chúng tôi không thể tải lên %1$s / %2$s kết quả đo lường. Nhật ký lỗi đã được chia sẻ với các nhà phát triển OONI. + Không tìm thấy tệp nhật ký + Không tìm thấy URL hợp lệ + JSON trống + Bạn có muốn tạm dừng bài kiểm tra này không? + Việc này sẽ làm gián đoạn bài kiểm tra hiện từ thời điểm này. + Bạn có muốn chạy tự động các bài kiểm tra này không? + Bằng việc bật kiểm tra tự động, bạn sẽ đóng góp thường xuyên các kết quả đo lường cho OONI. + Vui lòng cho phép ứng dụng chạy trên nền. + Nhắc lại tôi về sau + Đã sao chép vào clipboard + Chưa được tải lên + Tải lên + Một số chưa được tải lên + Tải lên tất cả + Trang web + Nhắn tin tức thời + Các middlebox + Hiệu suất + Vượt qua kiểm duyệt Internet + Thử nghiệm + Kiểm tra HTTP Invalid Request Line + Kiểm tra HTTP Header Field Manipulation + Kiểm tra Web Connectivity + Kiểm tra tốc độ NDT + Kiểm tra phát trực tuyến DASH + Kiểm tra WhatsApp + Kiểm tra Telegram + Kiểm tra Facebook Messenger + Kiểm tra Psiphon + Kiểm tra Tor + Kiểm tra RiseupVPN + Kiểm tra Signal + Cài đặt + Thời gian bạn đặt cho quá trình kiểm tra quá ngắn, + Giới thiệu về OONI + Quan sát mở về can thiệp mạng (OONI) là một dự án phần mềm miễn phí thuộc Dự án Tor nhằm mục đích tăng cường tính minh bạch của việc kiểm duyệt internet trên toàn thế giới.\n\nKể từ năm 2012, cộng đồng OONI toàn cầu đã mở rộng mạng lưới tại hơn 200 quốc gia. Một số các kết quả đo lường này là bằng chứng về sự kiểm duyệt internet. + Biết thêm + Blog + Báo cáo + Chính sách Dữ liệu của OONI + Thông báo + Được bật lên + Thông báo khi bài kiểm tra hoàn tất + Bài đăng mới + Kiểm tra tự động + Chạy kiểm tra tự động + Số lượng các bài kiểm tra tự động: %1$s. + Lần kiểm tra tự động gần đây nhất: %1$s. + Chỉ khi có WiFi + Chỉ khi đang sạc + Khi bật kiểm tra tự động, các bài kiểm tra OONI Probe sẽ tự động chạy nhiều lần mỗi ngày. Kết quả kiểm tra của bạn sẽ tự động được xuất bản trên OONI Explorer: https://explorer.ooni.org/\n\nQuan trọng: Nếu bạn bật VPN, OONI Probe sẽ không tự động chạy kiểm tra. Vui lòng tắt VPN của bạn để kiểm tra OONI Probe tự động. Tìm hiểu thêm: https://ooni.org/support/faq/#can-i-run-ooni-probe-over-a-vpn + Chia sẻ + Tự động công bố các kết quả + Tải lên thủ công kết quả + Bao gồm thông tin mạng + Bao gồm vị trí địa lý gần đúng + Bao gồm địa chỉ IP của tôi + Bao gồm Mã quốc gia + Thông tin này (ví dụ: IT là viết tắt của Italia) là bắt buộc để xác định quốc gia mà các đo lường được thu thập. Bạn có chắc chắn muốn tắt tùy chọn này không? + Bằng việc công bố kết quả, bạn đang góp phần tăng cường tính minh bạch trong can thiệp mạng và hỗ trợ cộng đồng OONI.\n\nThông tin mạng (ví dụ Số hệ thống tự trị - ASN) là bắt buộc để xác định Nhà cung cấp mạng + Các tùy chọn kiểm tra + Những gì bạn cấu hình thông qua cài đặt kiểm tra ở trên (ví dụ: tắt kiểm tra WhatsApp) sẽ áp dụng cho các bài kiểm tra chạy theo cách thủ công, cũng như các bài kiểm tra chạy tự động (khi kiểm tra tự động được bật). + Bài kiểm tra dài + Chạy bài kiểm tra dài ở foreground? + Riêng tư + Gửi báo cáo sự cố + Nâng cao + Chế độ tối + Nhật ký khắc phục lỗi + Xem nhật kí gần đây + Cài đặt Ngôn ngữ + Chọn Ngôn Ngữ + Luôn sử dụng domain fronting + Backend proxy của OONI + Proxy + Không có + Psiphon + Proxy tùy chỉnh + URL Proxy tùy chỉnh + Giao thức proxy tùy chỉnh + Kết nối + Tên máy chủ + Cổng + Thông tin xác thực (tùy chọn) + Tên đăng nhập + Mật khẩu + Sử dụng Psiphon thay cho proxy tùy chỉnh + Bạn không thể sử dụng OONI Probe? Hãy thử bật [Psiphon] (https://psiphon.ca/) để vượt qua kiểm duyệt lên OONI Probe. Hoặc, bạn có thể sử dụng proxy tùy chỉnh. + Giới hạn thời lượng kiểm tra + Thời gian kiểm tra + Các danh mục trang web để kiểm tra + %1$s danh mục đã bật + Chỉnh sửa + Bỏ chọn tất cả + Chọn Tất cả + Lưu + Thay đổi chưa được lưu + Bạn đã thực hiện một số thay đổi đối với các danh mục đã bật. Bạn có muốn lưu lại không? + Lưu + Bỏ qua + Chọn các trang web để kiểm tra + URL + Không có URL nào được nhập + Chạy + Thêm trang web + Tải từ biểu mẫu + Số lượng trang web được thử nghiệm (0 có nghĩa là tất cả) + Kiểm tra WhatsApp + Kiểm tra Telegram + Kiểm tra Facebook Messenger + Kiểm tra Signal + Chạy kiểm tra HTTP Invalid Request Line + Chạy kiểm tra HTTP Header Field Manipulation + Chạy kiểm tra tốc độ NDT + Lựa chọn máy chủ NDT tự động + Địa chỉ máy chủ NDT + Cổng máy chủ NDT + Chạy kiểm tra phát trực tuyến DASH + Tự động chọn máy chủ DASH + Máy chủ DASH + Cổng máy chủ DASH + Kiểm tra Psiphon + Kiểm tra Tor + Kiểm tra RiseupVPN + Cảnh báo khi VPN được sử dụng + Gửi email để hỗ trợ + Vui lòng mô tả vấn đề bạn đang gặp phải: + Vui lòng gửi email đến bug@openobservatory.org kèm theo thông tin về ứng dụng và phiên bản iOS. Nhấn vào \"Sao chép vào clipboard\" bên dưới để sao chép địa chỉ email của chúng tôi. + Ngôn ngữ hiện tại của ứng dụng là %1$s + Ngôn ngữ + Sử dụng bộ nhớ + Bộ nhớ đã sử dụng + Xóa + Xoá + Bạn chuẩn bị xóa tất cả các kết quả đo lường OONI khỏi thiết bị của mình. Nếu được tải lên, những kết quả này sẽ có trên [OONI Explorer] (https://explorer.ooni.org) + Đã chạy xong + Dừng kiểm tra + Thử tính năng mirror + Đang tải... + Đã xảy ra lỗi không mong muốn. Vui lòng tải lại trang này. + Bạn chuẩn bị chạy bài kiểm tra OONI Probe. + %1$s URL + Tên bài kiểm tra + Thông tin về bài kiểm tra + Chạy + Hết hạn + Bạn cần cài đặt phiên bản mới hơn của OONI Probe để chạy bài kiểm tra này. + Cập nhật + Đóng + Thông số không hợp lệ + Liên kết chạy OONI không đúng định dạng hoặc ứng dụng của bạn chưa được cập nhật. + Bạn sẽ kiểm tra một mẫu trang web ngẫu nhiên. + Vui lòng đợi cho bài kiểm tra hoàn thành trước khi nhấn vào liên kết chạy OONI. + Chất kích thích và Rượu + Tôn giáo + Nội dung khiêu dâm + Trang phục khêu gợi + Phê bình chính trị + Các vấn đề về nhân quyền + Môi trường + Chủ nghĩa khủng bố và các phần tử quá khích + Phát ngôn thù hận + Truyền thông tin tức + Giáo dục giới tính + Y tế công cộng + Cờ bạc + Các công cụ vượt kiểm duyệt + Hẹn hò trực tuyến + Mạng xã hội + LGBTQ+ + Chia sẻ file + Các công cụ lấy cắp dữ liệu + Các công cụ truyền thông + Chia sẻ truyền thông + Dịch vụ lưu trữ web và viết blog + Công cụ tìm kiếm + Game + Văn hóa + Kinh tế + Chính phủ + Thương mại điện tử + Nội dung kiểm soát + Tổ chức liên chính phủ + Nội dung khác + Sử dụng và mua bán chất kích thích và rượu + Các vấn đề tôn giáo, cả ủng hộ và phản biện + Nội dung khiêu dâm hardcore và softcore + Trang phục khêu gợi và hình ảnh phụ nữ mặc quần áo hở hang + Quan điểm chính trị quan trọng + Các vấn đề về nhân quyền + Thảo luận về các vấn đề môi trường + Chủ nghĩa khủng bố, các phần tử bạo lực hoặc phong trào ly khai + Phê phán các nhóm về chủng tộc, giới tính, xu hướng tính dục hoặc các đặc điểm khác + Các trang web tin tức lớn, các hãng tin tức khu vực và các phương tiện truyền thông độc lập + Các vấn đề sức khỏe tình dục bao gồm tránh thai, các bệnh lây qua đường tình dục, ngăn ngừa hiếp dâm và nạo phá thai + Các vấn đề về y tế công cộng, như COVID-19, HIV/AIDS, Ebola + Cờ bạc và cá độ trực truyến + Ẩn danh, vượt kiểm duyệt và mã hóa + Các trang hẹn hò trực tuyến + Các nền tảng và công cụ mạng xã hội trực tuyến + Cộng đồng LGBTQ + thảo luận về các vấn đề liên quan (trừ nội dung khiêu dâm) + Chia sẻ file bao gồm dữ liệu lưu trữ điện toán đám mây, torrent và P2P + Công cụ bảo mật máy tính và tin tức + Các công cụ giao tiếp cá nhân và nhóm bao gồm VoIP, nhắn tin và webmail + Chia sẻ video, âm thanh và hình ảnh + Lưu trữ web, viết blog và xuất bản trực tuyến khác + Công cụ tìm kiếm và cổng thông tin + Trò chơi trực tuyến và các nền tảng trò chơi (không bao gồm các trang web cờ bạc) + Giải trí, bao gồm lịch sử, văn học, âm nhạc, phim ảnh, châm biếm và hài + Tình hình chung về phát triển kinh tế và nghèo đói + Các trang web do chính phủ quản lý, bao gồm quân đội + Các sản phẩm và dịch vụ thương mại + Nội dung ôn hoà hoặc vô hại được sử dụng để kiểm soát + Các tổ chức liên chính phủ bao gồm Liên Hợp quốc + Các trang web chưa được phân loại + diff --git a/app/src/main/res/values/untraslatable.xml b/app/src/main/res/values/untraslatable.xml index 1201a1629..8e52cf58e 100644 --- a/app/src/main/res/values/untraslatable.xml +++ b/app/src/main/res/values/untraslatable.xml @@ -282,6 +282,8 @@ Kiswahili ไทย Türkçe + Tiếng Việt + မြန်မာ auto @@ -308,6 +310,8 @@ sw th tr + vi + my org.openobservatory.ooniprobe.activity.InfoActivity org.openobservatory.ooniprobe.activity.ProxyActivity From 9a7bd4f95619c78d21c987c2331c3755734d184d Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Fri, 18 Aug 2023 10:12:45 +0100 Subject: [PATCH 18/33] Chore: Update `DashboardFragment` to `ViewBinding` --- .../ooniprobe/fragment/DashboardFragment.java | 41 ++++++++----------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/DashboardFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/DashboardFragment.java index 0ebeb4d8d..7eee1ca50 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/DashboardFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/DashboardFragment.java @@ -1,31 +1,27 @@ package org.openobservatory.ooniprobe.fragment; -import android.content.Intent; import android.os.Bundle; import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.activity.AbstractActivity; -import org.openobservatory.ooniprobe.activity.MainActivity; import org.openobservatory.ooniprobe.activity.OverviewActivity; import org.openobservatory.ooniprobe.activity.RunningActivity; import org.openobservatory.ooniprobe.common.Application; import org.openobservatory.ooniprobe.common.PreferenceManager; import org.openobservatory.ooniprobe.common.ReachabilityManager; import org.openobservatory.ooniprobe.common.ThirdPartyServices; +import org.openobservatory.ooniprobe.databinding.FragmentDashboardBinding; import org.openobservatory.ooniprobe.item.SeperatorItem; import org.openobservatory.ooniprobe.item.TestsuiteItem; import org.openobservatory.ooniprobe.model.database.Result; @@ -33,43 +29,38 @@ import org.openobservatory.ooniprobe.test.suite.AbstractSuite; import java.util.ArrayList; -import java.util.Objects; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerAdapter; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; public class DashboardFragment extends Fragment implements View.OnClickListener { - @BindView(R.id.recycler) RecyclerView recycler; - @BindView(R.id.toolbar) Toolbar toolbar; - @BindView(R.id.last_tested) TextView lastTested; - @BindView(R.id.run_all) TextView runAll; - @BindView(R.id.vpn) TextView vpn; @Inject PreferenceManager preferenceManager; private ArrayList items; + private ArrayList testSuites; + private HeterogeneousRecyclerAdapter adapter; + private FragmentDashboardBinding binding; + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_dashboard, container, false); - ButterKnife.bind(this, v); + binding = FragmentDashboardBinding.inflate(inflater,container,false); ((Application) getActivity().getApplication()).getFragmentComponent().inject(this); - ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar); + ((AppCompatActivity) getActivity()).setSupportActionBar(binding.toolbar); ((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(null); items = new ArrayList<>(); testSuites = new ArrayList<>(); adapter = new HeterogeneousRecyclerAdapter<>(getActivity(), items); - recycler.setAdapter(adapter); - recycler.setLayoutManager(new LinearLayoutManager(getActivity())); - runAll.setOnClickListener(v1 -> runAll()); - vpn.setOnClickListener(view -> ((Application) getActivity().getApplication()).openVPNSettings()); - return v; + binding.recycler.setAdapter(adapter); + binding.recycler.setLayoutManager(new LinearLayoutManager(getActivity())); + binding.runAll.setOnClickListener(v1 -> runAll()); + binding.vpn.setOnClickListener(view -> ((Application) getActivity().getApplication()).openVPNSettings()); + return binding.getRoot(); } @Override public void onResume() { @@ -100,19 +91,19 @@ public class DashboardFragment extends Fragment implements View.OnClickListener adapter.notifyTypesChanged(); if (ReachabilityManager.isVPNinUse(this.getContext()) && preferenceManager.isWarnVPNInUse()) - vpn.setVisibility(View.VISIBLE); + binding.vpn.setVisibility(View.VISIBLE); else - vpn.setVisibility(View.GONE); + binding.vpn.setVisibility(View.GONE); } private void setLastTest() { Result lastResult = Result.getLastResult(); if (lastResult == null) - lastTested.setText(getString(R.string.Dashboard_Overview_LatestTest) + binding.lastTested.setText(getString(R.string.Dashboard_Overview_LatestTest) + " " + getString(R.string.Dashboard_Overview_LastRun_Never)); else - lastTested.setText(getString(R.string.Dashboard_Overview_LatestTest) + binding.lastTested.setText(getString(R.string.Dashboard_Overview_LatestTest) + " " + DateUtils.getRelativeTimeSpanString(lastResult.start_time.getTime())); } From 0182e6117bca1639a5e1c85595862afb5c797a22 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sat, 26 Aug 2023 16:40:13 +0100 Subject: [PATCH 19/33] Replace `Butterknife` in `TestsuiteItem` --- .../ooniprobe/item/TestsuiteItem.java | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/TestsuiteItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/TestsuiteItem.java index 98fb0f70c..9eb8bf60b 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/TestsuiteItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/TestsuiteItem.java @@ -1,27 +1,18 @@ package org.openobservatory.ooniprobe.item; -import android.content.Context; import android.content.res.Resources; -import android.graphics.Color; import android.graphics.PorterDuff; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - import androidx.cardview.widget.CardView; -import androidx.constraintlayout.widget.ConstraintLayout; import androidx.recyclerview.widget.RecyclerView; - +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.PreferenceManager; +import org.openobservatory.ooniprobe.databinding.ItemTestsuiteBinding; import org.openobservatory.ooniprobe.test.suite.AbstractSuite; -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - public class TestsuiteItem extends HeterogeneousRecyclerItem { private final View.OnClickListener onClickListener; private final PreferenceManager preferenceManager; @@ -33,21 +24,21 @@ public TestsuiteItem(AbstractSuite extra, View.OnClickListener onClickListener, } @Override public ViewHolderImpl onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolderImpl(layoutInflater.inflate(R.layout.item_testsuite, viewGroup, false)); + return new ViewHolderImpl(ItemTestsuiteBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolderImpl holder) { - holder.title.setText(extra.getTitle()); - holder.desc.setText(extra.getCardDesc()); - holder.icon.setImageResource(extra.getIconGradient()); + holder.binding.title.setText(extra.getTitle()); + holder.binding.desc.setText(extra.getCardDesc()); + holder.binding.icon.setImageResource(extra.getIconGradient()); holder.itemView.setTag(extra); if(extra.isTestEmpty(preferenceManager)) { ((CardView)holder.itemView).setElevation(0); Resources resources = holder.itemView.getContext().getResources(); ((CardView)holder.itemView).setCardBackgroundColor(resources.getColor(R.color.disabled_test_background)); - holder.title.setTextColor(resources.getColor(R.color.disabled_test_text)); - holder.desc.setTextColor(resources.getColor(R.color.disabled_test_text)); - holder.icon.setColorFilter(resources.getColor(R.color.disabled_test_text), PorterDuff.Mode.SRC_IN); + holder.binding.title.setTextColor(resources.getColor(R.color.disabled_test_text)); + holder.binding.desc.setTextColor(resources.getColor(R.color.disabled_test_text)); + holder.binding.icon.setColorFilter(resources.getColor(R.color.disabled_test_text), PorterDuff.Mode.SRC_IN); holder.setIsRecyclable(false); holder.itemView.setClickable(false); } else { @@ -55,14 +46,12 @@ public TestsuiteItem(AbstractSuite extra, View.OnClickListener onClickListener, } } - class ViewHolderImpl extends RecyclerView.ViewHolder { - @BindView(R.id.title) TextView title; - @BindView(R.id.desc) TextView desc; - @BindView(R.id.icon) ImageView icon; + static class ViewHolderImpl extends RecyclerView.ViewHolder { + ItemTestsuiteBinding binding; - ViewHolderImpl(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolderImpl(ItemTestsuiteBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } From ef2713958a9434ae3575bc6a76fa4180dbedef16 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sat, 26 Aug 2023 16:45:24 +0100 Subject: [PATCH 20/33] Update `CustomWebsiteActivity` to `ViewBinding` --- .../activity/CustomWebsiteActivity.java | 39 +++++++------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/CustomWebsiteActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/CustomWebsiteActivity.java index d4762e534..bef139f13 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/CustomWebsiteActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/CustomWebsiteActivity.java @@ -1,55 +1,42 @@ package org.openobservatory.ooniprobe.activity; import android.content.DialogInterface; -import android.content.Intent; import android.os.Bundle; import android.util.Patterns; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.ImageButton; -import android.widget.LinearLayout; - import androidx.annotation.Nullable; -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.ActivityCompat; - +import localhost.toolkit.app.fragment.ConfirmDialogFragment; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.PreferenceManager; +import org.openobservatory.ooniprobe.databinding.ActivityCustomwebsiteBinding; import org.openobservatory.ooniprobe.model.database.Url; import org.openobservatory.ooniprobe.test.suite.WebsitesSuite; +import javax.inject.Inject; import java.io.Serializable; import java.util.ArrayList; -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import localhost.toolkit.app.fragment.ConfirmDialogFragment; - public class CustomWebsiteActivity extends AbstractActivity implements ConfirmDialogFragment.OnConfirmedListener { - @BindView(R.id.urlContainer) - LinearLayout urlContainer; - @BindView(R.id.bottomBar) - Toolbar bottomBar; private ArrayList editTexts; private ArrayList deletes; @Inject PreferenceManager preferenceManager; + private ActivityCustomwebsiteBinding binding; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActivityComponent().inject(this); - setContentView(R.layout.activity_customwebsite); - ButterKnife.bind(this); + binding = ActivityCustomwebsiteBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); editTexts = new ArrayList<>(); deletes = new ArrayList<>(); - bottomBar.inflateMenu(R.menu.run); - bottomBar.setOnMenuItemClickListener(item -> { + binding.bottomBar.inflateMenu(R.menu.run); + binding.bottomBar.setOnMenuItemClickListener(item -> { if (!checkPrefix()) return false; ArrayList urls = new ArrayList<>(editTexts.size()); @@ -66,6 +53,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { RunningActivity.runAsForegroundService(CustomWebsiteActivity.this, suite.asArray(), this::finish, preferenceManager); return true; }); + binding.add.setOnClickListener(v -> add()); add(); } @@ -103,12 +91,11 @@ public boolean onSupportNavigateUp() { return true; } - @OnClick(R.id.add) void add() { - ViewGroup urlBox = (ViewGroup) getLayoutInflater().inflate(R.layout.edittext_url, urlContainer, false); + ViewGroup urlBox = (ViewGroup) getLayoutInflater().inflate(R.layout.edittext_url, binding.urlContainer, false); EditText editText = urlBox.findViewById(R.id.editText); editTexts.add(editText); - urlContainer.addView(urlBox); + binding.urlContainer.addView(urlBox); ImageButton delete = urlBox.findViewById(R.id.delete); deletes.add(delete); delete.setTag(editText); @@ -117,11 +104,11 @@ void add() { ((View) v.getParent()).setVisibility(View.GONE); editTexts.remove(tag); deletes.remove(v); - bottomBar.setTitle(getString(R.string.OONIRun_URLs, Integer.toString(editTexts.size()))); + binding.bottomBar.setTitle(getString(R.string.OONIRun_URLs, Integer.toString(editTexts.size()))); setVisibilityDelete(); }); setVisibilityDelete(); - bottomBar.setTitle(getString(R.string.OONIRun_URLs, Integer.toString(editTexts.size()))); + binding.bottomBar.setTitle(getString(R.string.OONIRun_URLs, Integer.toString(editTexts.size()))); } private void setVisibilityDelete() { From bd25e4f93c2aed81420e6c757477bd6db310eaa2 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sat, 26 Aug 2023 16:50:57 +0100 Subject: [PATCH 21/33] Update `InfoActivity` to `ViewBinding` --- .../ooniprobe/activity/InfoActivity.java | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/InfoActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/InfoActivity.java index 3a75eace3..b418f26df 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/InfoActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/InfoActivity.java @@ -3,44 +3,40 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.widget.TextView; - import androidx.annotation.Nullable; -import androidx.appcompat.widget.Toolbar; - import org.openobservatory.ooniprobe.BuildConfig; import org.openobservatory.ooniprobe.R; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; +import org.openobservatory.ooniprobe.databinding.ActivityInfoBinding; public class InfoActivity extends AbstractActivity { - @BindView(R.id.toolbar) Toolbar toolbar; - @BindView(R.id.version) TextView version; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_info); - ButterKnife.bind(this); - setSupportActionBar(toolbar); + ActivityInfoBinding binding = ActivityInfoBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + setSupportActionBar(binding.toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); - version.setText(getString(R.string.version, BuildConfig.SOFTWARE_NAME, BuildConfig.VERSION_NAME)); + binding.version.setText(getString(R.string.version, BuildConfig.SOFTWARE_NAME, BuildConfig.VERSION_NAME)); + + binding.blog.setOnClickListener(v -> onBlogClick()); + binding.reports.setOnClickListener(v -> onReportsClick()); + binding.learnMore.setOnClickListener(v -> onLearnMoreClick()); + binding.dataPolicy.setOnClickListener(v -> onDataPolicyClick()); } - @OnClick(R.id.blog) void onBlogClick() { + void onBlogClick() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://ooni.org/blog/"))); } - @OnClick(R.id.reports) void onReportsClick() { + void onReportsClick() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://ooni.org/reports/"))); } - @OnClick(R.id.learnMore) void onLearnMoreClick() { + void onLearnMoreClick() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://ooni.org/"))); } - @OnClick(R.id.dataPolicy) void onDataPolicyClick() { + void onDataPolicyClick() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://ooni.org/about/data-policy/"))); } } From 1f2cbab072b206cc0f34f7ea225766038615744e Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sat, 26 Aug 2023 18:08:21 +0100 Subject: [PATCH 22/33] Update `MeasurementDetailActivity` and component fragment to use `ViewBinding` --- .../activity/MeasurementDetailActivity.java | 84 +++++-------------- .../fragment/measurement/DashFragment.java | 22 ++--- .../FacebookMessengerFragment.java | 30 +++---- .../fragment/measurement/FailedFragment.java | 6 +- .../measurement/HeaderNdtFragment.java | 28 +++---- .../measurement/HeaderOutcomeFragment.java | 22 ++--- .../HttpHeaderFieldManipulationFragment.java | 19 ++--- .../HttpInvalidRequestLineFragment.java | 19 ++--- .../fragment/measurement/NdtFragment.java | 24 ++---- .../fragment/measurement/PsiphonFragment.java | 18 ++-- .../measurement/RiseupVPNFragment.java | 24 ++---- .../fragment/measurement/SignalFragment.java | 15 +--- .../measurement/TelegramFragment.java | 29 +++---- .../fragment/measurement/TorFragment.java | 25 ++---- .../measurement/WebConnectivityFragment.java | 21 ++--- .../measurement/WhatsappFragment.java | 34 +++----- 16 files changed, 138 insertions(+), 282 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/MeasurementDetailActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/MeasurementDetailActivity.java index 1e00ceb1d..91bdc4dfd 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/MeasurementDetailActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/MeasurementDetailActivity.java @@ -8,87 +8,41 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.widget.Button; -import android.widget.TextView; - import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.widget.Toolbar; -import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.fragment.app.Fragment; - import com.google.android.material.snackbar.Snackbar; import com.google.gson.Gson; - +import localhost.toolkit.app.fragment.ConfirmDialogFragment; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.PreferenceManager; import org.openobservatory.ooniprobe.common.ResubmitTask; +import org.openobservatory.ooniprobe.databinding.ActivityMeasurementDetailBinding; import org.openobservatory.ooniprobe.domain.GetTestSuite; import org.openobservatory.ooniprobe.domain.MeasurementsManager; import org.openobservatory.ooniprobe.domain.callback.DomainCallback; -import org.openobservatory.ooniprobe.fragment.measurement.DashFragment; -import org.openobservatory.ooniprobe.fragment.measurement.FacebookMessengerFragment; -import org.openobservatory.ooniprobe.fragment.measurement.FailedFragment; -import org.openobservatory.ooniprobe.fragment.measurement.HeaderNdtFragment; -import org.openobservatory.ooniprobe.fragment.measurement.HeaderOutcomeFragment; -import org.openobservatory.ooniprobe.fragment.measurement.HttpHeaderFieldManipulationFragment; -import org.openobservatory.ooniprobe.fragment.measurement.HttpInvalidRequestLineFragment; -import org.openobservatory.ooniprobe.fragment.measurement.NdtFragment; -import org.openobservatory.ooniprobe.fragment.measurement.PsiphonFragment; -import org.openobservatory.ooniprobe.fragment.measurement.RiseupVPNFragment; -import org.openobservatory.ooniprobe.fragment.measurement.SignalFragment; -import org.openobservatory.ooniprobe.fragment.measurement.TelegramFragment; -import org.openobservatory.ooniprobe.fragment.measurement.TorFragment; -import org.openobservatory.ooniprobe.fragment.measurement.WebConnectivityFragment; -import org.openobservatory.ooniprobe.fragment.measurement.WhatsappFragment; +import org.openobservatory.ooniprobe.fragment.measurement.*; import org.openobservatory.ooniprobe.fragment.resultHeader.ResultHeaderDetailFragment; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Network; import org.openobservatory.ooniprobe.test.suite.PerformanceSuite; -import org.openobservatory.ooniprobe.test.test.Dash; -import org.openobservatory.ooniprobe.test.test.FacebookMessenger; -import org.openobservatory.ooniprobe.test.test.HttpHeaderFieldManipulation; -import org.openobservatory.ooniprobe.test.test.HttpInvalidRequestLine; -import org.openobservatory.ooniprobe.test.test.Ndt; -import org.openobservatory.ooniprobe.test.test.Psiphon; -import org.openobservatory.ooniprobe.test.test.RiseupVPN; -import org.openobservatory.ooniprobe.test.test.Signal; -import org.openobservatory.ooniprobe.test.test.Telegram; -import org.openobservatory.ooniprobe.test.test.Tor; -import org.openobservatory.ooniprobe.test.test.WebConnectivity; -import org.openobservatory.ooniprobe.test.test.Whatsapp; +import org.openobservatory.ooniprobe.test.test.*; +import ru.noties.markwon.Markwon; +import javax.inject.Inject; import java.io.Serializable; import java.util.Collections; import java.util.Objects; -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import localhost.toolkit.app.fragment.ConfirmDialogFragment; -import ru.noties.markwon.Markwon; - public class MeasurementDetailActivity extends AbstractActivity implements ConfirmDialogFragment.OnConfirmedListener { private static final String ID = "id"; private static final String RERUN_KEY = "rerun"; - @BindView(R.id.coordinatorLayout) - CoordinatorLayout coordinatorLayout; - @BindView(R.id.toolbar) - Toolbar toolbar; + private Boolean isInExplorer; + private Measurement measurement; + private Snackbar snackbar; - private Boolean isInExplorer; - @BindView(R.id.log) - Button log; - @BindView(R.id.explorer) - Button explorer; - @BindView(R.id.data) - Button data; - @BindView(R.id.methodology) - TextView methodology; @Inject MeasurementsManager measurementsManager; @@ -121,9 +75,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { measurement.is_anomaly ? R.style.Theme_MaterialComponents_Light_DarkActionBar_App_NoActionBar_Failure : R.style.Theme_MaterialComponents_Light_DarkActionBar_App_NoActionBar_Success); - setContentView(R.layout.activity_measurement_detail); - ButterKnife.bind(this); - setSupportActionBar(toolbar); + ActivityMeasurementDetailBinding binding = ActivityMeasurementDetailBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + setSupportActionBar(binding.toolbar); ActionBar bar = getSupportActionBar(); if (bar != null) { bar.setDisplayHomeAsUpEnabled(true); @@ -237,7 +191,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { .replace(R.id.body, detail) .replace(R.id.head, head) .commit(); - snackbar = Snackbar.make(coordinatorLayout, R.string.Snackbar_ResultsNotUploaded_Text, Snackbar.LENGTH_INDEFINITE) + snackbar = Snackbar.make(binding.coordinatorLayout, R.string.Snackbar_ResultsNotUploaded_Text, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.Snackbar_ResultsNotUploaded_Upload, v1 -> runAsyncTask()); Context c = this; isInExplorer = !measurement.hasReportFile(c); @@ -255,11 +209,14 @@ public void onError(String msg) { }); if (!measurement.hasLogFile(this)) - log.setVisibility(View.GONE); + binding.log.setVisibility(View.GONE); if (!measurementsManager.hasReportId(measurement)) - explorer.setVisibility(View.GONE); - Markwon.setMarkdown(methodology, getString(R.string.TestResults_Details_Methodology_Paragraph, getString(measurement.getTest().getUrlResId()))); + binding.explorer.setVisibility(View.GONE); + Markwon.setMarkdown(binding.methodology, getString(R.string.TestResults_Details_Methodology_Paragraph, getString(measurement.getTest().getUrlResId()))); load(); + binding.log.setOnClickListener(v -> logClick()); + binding.data.setOnClickListener(v -> dataClick()); + binding.explorer.setOnClickListener(v -> explorerClick()); } private void runAsyncTask() { @@ -305,17 +262,14 @@ public boolean onOptionsItemSelected(MenuItem item) { } } - @OnClick(R.id.log) void logClick() { startActivity(TextActivity.newIntent(this, TextActivity.TYPE_LOG, measurement)); } - @OnClick(R.id.data) void dataClick() { startActivity(TextActivity.newIntent(this, TextActivity.TYPE_JSON, measurement)); } - @OnClick(R.id.explorer) void explorerClick() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(measurementsManager.getExplorerUrl(measurement)))); } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/DashFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/DashFragment.java index d5f29b7e9..ed6d8c58d 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/DashFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/DashFragment.java @@ -5,22 +5,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementDashBinding; import org.openobservatory.ooniprobe.model.database.Measurement; -import butterknife.BindView; -import butterknife.ButterKnife; - public class DashFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.medianBitrate) TextView medianBitrate; - @BindView(R.id.playoutDelay) TextView playoutDelay; public static DashFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -30,14 +23,15 @@ public static DashFragment newInstance(Measurement measurement) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_dash, container, false); - ButterKnife.bind(this, v); - medianBitrate.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getMedianBitrate(getActivity()), getString(measurement.getTestKeys().getMedianBitrateUnit())))); - playoutDelay.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getPlayoutDelay(getActivity()), "s"))); - return v; + FragmentMeasurementDashBinding binding = FragmentMeasurementDashBinding.inflate(inflater,container,false); + binding.medianBitrate.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getMedianBitrate(getActivity()), getString(measurement.getTestKeys().getMedianBitrateUnit())))); + binding.playoutDelay.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getPlayoutDelay(getActivity()), "s"))); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/FacebookMessengerFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/FacebookMessengerFragment.java index 4792e9963..b3613c949 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/FacebookMessengerFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/FacebookMessengerFragment.java @@ -4,25 +4,16 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementFacebookmessengerBinding; import org.openobservatory.ooniprobe.model.database.Measurement; -import butterknife.BindView; -import butterknife.ButterKnife; - public class FacebookMessengerFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.tcp) TextView tcp; - @BindView(R.id.dns) TextView dns; - @BindView(R.id.desc) TextView desc; - public static FacebookMessengerFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); args.putSerializable(MEASUREMENT, measurement); @@ -31,19 +22,20 @@ public static FacebookMessengerFragment newInstance(Measurement measurement) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_facebookmessenger, container, false); - ButterKnife.bind(this, v); - desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_InstantMessaging_FacebookMessenger_LikelyBlocked_Content_Paragraph : R.string.TestResults_Details_InstantMessaging_FacebookMessenger_Reachable_Content_Paragraph); - dns.setText(measurement.getTestKeys().getFacebookMessengerDns()); + FragmentMeasurementFacebookmessengerBinding binding = FragmentMeasurementFacebookmessengerBinding.inflate(inflater,container,false); + binding.desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_InstantMessaging_FacebookMessenger_LikelyBlocked_Content_Paragraph : R.string.TestResults_Details_InstantMessaging_FacebookMessenger_Reachable_Content_Paragraph); + binding.dns.setText(measurement.getTestKeys().getFacebookMessengerDns()); if (Boolean.TRUE.equals(measurement.getTestKeys().facebook_dns_blocking)) - dns.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); - tcp.setText(measurement.getTestKeys().getFacebookMessengerTcp()); + binding.dns.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); + binding.tcp.setText(measurement.getTestKeys().getFacebookMessengerTcp()); if (Boolean.TRUE.equals(measurement.getTestKeys().facebook_tcp_blocking)) - tcp.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); - return v; + binding.tcp.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/FailedFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/FailedFragment.java index 6b04f8c92..ba9f6f98a 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/FailedFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/FailedFragment.java @@ -37,13 +37,15 @@ public static FailedFragment newInstance(Measurement measurement) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { binding = FragmentMeasurementFailedBinding.inflate(inflater,container,false); binding.tryAgain.setOnClickListener(this::tryAgainClick); return binding.getRoot(); } - void tryAgainClick(View view) { + void tryAgainClick(View view) { assert getArguments() != null; Measurement failedMeasurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert failedMeasurement != null; diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HeaderNdtFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HeaderNdtFragment.java index 04bab8f95..2467cf99e 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HeaderNdtFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HeaderNdtFragment.java @@ -5,24 +5,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementHeaderNdtBinding; import org.openobservatory.ooniprobe.model.database.Measurement; -import butterknife.BindView; -import butterknife.ButterKnife; - public class HeaderNdtFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.download) TextView download; - @BindView(R.id.upload) TextView upload; - @BindView(R.id.ping) TextView ping; - @BindView(R.id.server) TextView server; public static HeaderNdtFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -32,16 +23,17 @@ public static HeaderNdtFragment newInstance(Measurement measurement) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_header_ndt, container, false); - ButterKnife.bind(this, v); - download.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getDownload(getActivity()), getString(measurement.getTestKeys().getDownloadUnit())))); - upload.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getUpload(getActivity()), getString(measurement.getTestKeys().getUploadUnit())))); - ping.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getPing(getActivity()), "ms"))); - server.setText(measurement.getTestKeys().getServerDetails(getActivity())); - return v; + FragmentMeasurementHeaderNdtBinding binding = FragmentMeasurementHeaderNdtBinding.inflate(inflater,container,false); + binding.download.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getDownload(getActivity()), getString(measurement.getTestKeys().getDownloadUnit())))); + binding.upload.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getUpload(getActivity()), getString(measurement.getTestKeys().getUploadUnit())))); + binding.ping.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getPing(getActivity()), "ms"))); + binding.server.setText(measurement.getTestKeys().getServerDetails(getActivity())); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HeaderOutcomeFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HeaderOutcomeFragment.java index 164b9361c..52af50b58 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HeaderOutcomeFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HeaderOutcomeFragment.java @@ -5,21 +5,14 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - -import org.openobservatory.ooniprobe.R; - -import butterknife.BindView; -import butterknife.ButterKnife; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementHeaderOutcomeBinding; public class HeaderOutcomeFragment extends Fragment { public static final String ICON_RES = "iconRes"; private static final String DESC = "desc"; - @BindView(R.id.outcome) TextView outcome; public static HeaderOutcomeFragment newInstance(Integer iconRes, String desc) { Bundle args = new Bundle(); @@ -31,13 +24,14 @@ public static HeaderOutcomeFragment newInstance(Integer iconRes, String desc) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { assert getArguments() != null; - View v = inflater.inflate(R.layout.fragment_measurement_header_outcome, container, false); - ButterKnife.bind(this, v); - outcome.setText(Html.fromHtml(getArguments().getString(DESC))); + FragmentMeasurementHeaderOutcomeBinding binding = FragmentMeasurementHeaderOutcomeBinding.inflate(inflater,container,false); + binding.outcome.setText(Html.fromHtml(getArguments().getString(DESC))); if (getArguments().containsKey(ICON_RES)) - outcome.setCompoundDrawablesRelativeWithIntrinsicBounds(0, getArguments().getInt(ICON_RES), 0, 0); - return v; + binding.outcome.setCompoundDrawablesRelativeWithIntrinsicBounds(0, getArguments().getInt(ICON_RES), 0, 0); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HttpHeaderFieldManipulationFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HttpHeaderFieldManipulationFragment.java index 7dccf0034..aca7b2cd6 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HttpHeaderFieldManipulationFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HttpHeaderFieldManipulationFragment.java @@ -4,21 +4,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementHttpheaderfieldmanipulationBinding; import org.openobservatory.ooniprobe.model.database.Measurement; -import butterknife.BindView; -import butterknife.ButterKnife; - public class HttpHeaderFieldManipulationFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.desc) TextView desc; public static HttpHeaderFieldManipulationFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -28,13 +22,14 @@ public static HttpHeaderFieldManipulationFragment newInstance(Measurement measur return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_httpheaderfieldmanipulation, container, false); - ButterKnife.bind(this, v); - desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_Middleboxes_HTTPHeaderFieldManipulation_Found_Content_Paragraph : R.string.TestResults_Details_Middleboxes_HTTPHeaderFieldManipulation_NotFound_Content_Paragraph); - return v; + FragmentMeasurementHttpheaderfieldmanipulationBinding binding = FragmentMeasurementHttpheaderfieldmanipulationBinding.inflate(inflater,container,false); + binding.desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_Middleboxes_HTTPHeaderFieldManipulation_Found_Content_Paragraph : R.string.TestResults_Details_Middleboxes_HTTPHeaderFieldManipulation_NotFound_Content_Paragraph); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HttpInvalidRequestLineFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HttpInvalidRequestLineFragment.java index 0c2135abf..aa3015b3e 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HttpInvalidRequestLineFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/HttpInvalidRequestLineFragment.java @@ -4,21 +4,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementHttpinvalidrequestlineBinding; import org.openobservatory.ooniprobe.model.database.Measurement; -import butterknife.BindView; -import butterknife.ButterKnife; - public class HttpInvalidRequestLineFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.desc) TextView desc; public static HttpInvalidRequestLineFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -28,13 +22,14 @@ public static HttpInvalidRequestLineFragment newInstance(Measurement measurement return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_httpinvalidrequestline, container, false); - ButterKnife.bind(this, v); - desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_Middleboxes_HTTPInvalidRequestLine_Found_Content_Paragraph : R.string.TestResults_Details_Middleboxes_HTTPInvalidRequestLine_NotFound_Content_Paragraph); - return v; + FragmentMeasurementHttpinvalidrequestlineBinding biding = FragmentMeasurementHttpinvalidrequestlineBinding.inflate(inflater,container,false); + biding.desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_Middleboxes_HTTPInvalidRequestLine_Found_Content_Paragraph : R.string.TestResults_Details_Middleboxes_HTTPInvalidRequestLine_NotFound_Content_Paragraph); + return biding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/NdtFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/NdtFragment.java index 16596a393..1223c562f 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/NdtFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/NdtFragment.java @@ -5,24 +5,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementNdtBinding; import org.openobservatory.ooniprobe.model.database.Measurement; -import butterknife.BindView; -import butterknife.ButterKnife; - public class NdtFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.packetLoss) TextView packetLoss; - @BindView(R.id.averagePing) TextView averagePing; - @BindView(R.id.maxPing) TextView maxPing; - @BindView(R.id.mss) TextView mss; public static NdtFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -36,12 +27,11 @@ public static NdtFragment newInstance(Measurement measurement) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_ndt, container, false); - ButterKnife.bind(this, v); - packetLoss.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getPacketLoss(getActivity()), "%"))); - averagePing.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getAveragePing(getActivity()), "ms"))); - maxPing.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getMaxPing(getActivity()), "ms"))); - mss.setText(measurement.getTestKeys().getMSS(getActivity())); - return v; + FragmentMeasurementNdtBinding binding = FragmentMeasurementNdtBinding.inflate(inflater,container,false); + binding.packetLoss.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getPacketLoss(getActivity()), "%"))); + binding.averagePing.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getAveragePing(getActivity()), "ms"))); + binding.maxPing.setText(Html.fromHtml(getString(R.string.bigNormal, measurement.getTestKeys().getMaxPing(getActivity()), "ms"))); + binding.mss.setText(measurement.getTestKeys().getMSS(getActivity())); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/PsiphonFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/PsiphonFragment.java index 33755b2fc..ae697cff3 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/PsiphonFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/PsiphonFragment.java @@ -4,23 +4,16 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementPsiphonBinding; import org.openobservatory.ooniprobe.model.database.Measurement; - -import butterknife.BindView; -import butterknife.ButterKnife; import ru.noties.markwon.Markwon; public class PsiphonFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.bootstrap) TextView bootstrap; - @BindView(R.id.desc) TextView desc; public static PsiphonFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -34,14 +27,13 @@ public static PsiphonFragment newInstance(Measurement measurement) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_psiphon, container, false); - ButterKnife.bind(this, v); - Markwon.setMarkdown(desc, + FragmentMeasurementPsiphonBinding binding = FragmentMeasurementPsiphonBinding.inflate(inflater,container,false); + Markwon.setMarkdown(binding.desc, measurement.is_anomaly ? getString(R.string.TestResults_Details_Circumvention_Psiphon_Blocked_Content_Paragraph) : getString(R.string.TestResults_Details_Circumvention_Psiphon_Reachable_Content_Paragraph) ); - bootstrap.setText(measurement.getTestKeys().getBootstrapTime(getActivity())); - return v; + binding.bootstrap.setText(measurement.getTestKeys().getBootstrapTime(getActivity())); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/RiseupVPNFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/RiseupVPNFragment.java index c0bddd732..83670bd5e 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/RiseupVPNFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/RiseupVPNFragment.java @@ -4,25 +4,16 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementRiseupvpnBinding; import org.openobservatory.ooniprobe.model.database.Measurement; - -import butterknife.BindView; -import butterknife.ButterKnife; import ru.noties.markwon.Markwon; public class RiseupVPNFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.bootstrap_value) TextView bootstrap_value; - @BindView(R.id.openvpn_value) TextView openvpn_value; - @BindView(R.id.bridges_value) TextView bridges_value; - @BindView(R.id.desc) TextView desc; public static RiseupVPNFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -36,16 +27,15 @@ public static RiseupVPNFragment newInstance(Measurement measurement) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_riseupvpn, container, false); - ButterKnife.bind(this, v); - Markwon.setMarkdown(desc, + FragmentMeasurementRiseupvpnBinding binding = FragmentMeasurementRiseupvpnBinding.inflate(inflater,container,false); + Markwon.setMarkdown(binding.desc, measurement.is_anomaly ? getString(R.string.TestResults_Details_Circumvention_RiseupVPN_Blocked_Content_Paragraph) : getString(R.string.TestResults_Details_Circumvention_RiseupVPN_Reachable_Content_Paragraph) ); - bootstrap_value.setText(measurement.getTestKeys().getRiseupVPNApiStatus()); - openvpn_value.setText(measurement.getTestKeys().getRiseupVPNOpenvpnGatewayStatus(getContext())); - bridges_value.setText(measurement.getTestKeys().getRiseupVPNBridgedGatewayStatus(getContext())); - return v; + binding.bootstrapValue.setText(measurement.getTestKeys().getRiseupVPNApiStatus()); + binding.openvpnValue.setText(measurement.getTestKeys().getRiseupVPNOpenvpnGatewayStatus(getContext())); + binding.bridgesValue.setText(measurement.getTestKeys().getRiseupVPNBridgedGatewayStatus(getContext())); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/SignalFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/SignalFragment.java index 869345136..aa395e3d9 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/SignalFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/SignalFragment.java @@ -4,21 +4,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementSignalBinding; import org.openobservatory.ooniprobe.model.database.Measurement; -import butterknife.BindView; -import butterknife.ButterKnife; - public class SignalFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.desc) TextView desc; public static SignalFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -32,9 +26,8 @@ public static SignalFragment newInstance(Measurement measurement) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_signal, container, false); - ButterKnife.bind(this, v); - desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_InstantMessaging_Signal_LikelyBlocked_Content_Paragraph : R.string.TestResults_Details_InstantMessaging_Signal_Reachable_Content_Paragraph); - return v; + FragmentMeasurementSignalBinding binding = FragmentMeasurementSignalBinding.inflate(inflater,container,false); + binding.desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_InstantMessaging_Signal_LikelyBlocked_Content_Paragraph : R.string.TestResults_Details_InstantMessaging_Signal_Reachable_Content_Paragraph); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/TelegramFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/TelegramFragment.java index da689104a..3c1e8920e 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/TelegramFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/TelegramFragment.java @@ -4,25 +4,17 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementTelegramBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.jsonresult.TestKeys; -import butterknife.BindView; -import butterknife.ButterKnife; - public class TelegramFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.application) TextView application; - @BindView(R.id.webApp) TextView webApp; - @BindView(R.id.desc) TextView desc; public static TelegramFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -32,19 +24,20 @@ public static TelegramFragment newInstance(Measurement measurement) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_telegram, container, false); - ButterKnife.bind(this, v); - desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_InstantMessaging_Telegram_LikelyBlocked_Content_Paragraph : R.string.TestResults_Details_InstantMessaging_Telegram_Reachable_Content_Paragraph); - application.setText(measurement.getTestKeys().getTelegramEndpointStatus()); + FragmentMeasurementTelegramBinding binding = FragmentMeasurementTelegramBinding.inflate(inflater,container,false); + binding.desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_InstantMessaging_Telegram_LikelyBlocked_Content_Paragraph : R.string.TestResults_Details_InstantMessaging_Telegram_Reachable_Content_Paragraph); + binding.application.setText(measurement.getTestKeys().getTelegramEndpointStatus()); if (Boolean.TRUE.equals(measurement.getTestKeys().telegram_http_blocking) || Boolean.TRUE.equals(measurement.getTestKeys().telegram_tcp_blocking)) - application.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); - webApp.setText(measurement.getTestKeys().getTelegramWebStatus()); + binding.application.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); + binding.webApp.setText(measurement.getTestKeys().getTelegramWebStatus()); if (TestKeys.BLOCKED.equals(measurement.getTestKeys().telegram_web_status)) - webApp.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); - return v; + binding.webApp.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/TorFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/TorFragment.java index 4140994f6..3b47b9dcd 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/TorFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/TorFragment.java @@ -4,24 +4,16 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementTorBinding; import org.openobservatory.ooniprobe.model.database.Measurement; - -import butterknife.BindView; -import butterknife.ButterKnife; import ru.noties.markwon.Markwon; public class TorFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.bridges) TextView bridges; - @BindView(R.id.authorities) TextView authorities; - @BindView(R.id.desc) TextView desc; public static TorFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -31,19 +23,20 @@ public static TorFragment newInstance(Measurement measurement) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_tor, container, false); - ButterKnife.bind(this, v); - Markwon.setMarkdown(desc, + FragmentMeasurementTorBinding binding = FragmentMeasurementTorBinding.inflate(inflater,container,false); + Markwon.setMarkdown(binding.desc, measurement.is_anomaly ? getString(R.string.TestResults_Details_Circumvention_Tor_Blocked_Content_Paragraph) : getString(R.string.TestResults_Details_Circumvention_Tor_Reachable_Content_Paragraph) ); - bridges.setText(measurement.getTestKeys().getBridges(getActivity())); - authorities.setText(measurement.getTestKeys().getAuthorities(getActivity())); - return v; + binding.bridges.setText(measurement.getTestKeys().getBridges(getActivity())); + binding.authorities.setText(measurement.getTestKeys().getAuthorities(getActivity())); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/WebConnectivityFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/WebConnectivityFragment.java index 5f0fb32cf..e39131b45 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/WebConnectivityFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/WebConnectivityFragment.java @@ -4,22 +4,16 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementWebconnectivityBinding; import org.openobservatory.ooniprobe.model.database.Measurement; - -import butterknife.BindView; -import butterknife.ButterKnife; import ru.noties.markwon.Markwon; public class WebConnectivityFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.desc) TextView desc; public static WebConnectivityFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -29,16 +23,17 @@ public static WebConnectivityFragment newInstance(Measurement measurement) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_webconnectivity, container, false); - ButterKnife.bind(this, v); + FragmentMeasurementWebconnectivityBinding binding = FragmentMeasurementWebconnectivityBinding.inflate(inflater,container,false); if (measurement.is_anomaly) - Markwon.setMarkdown(desc, getString(R.string.TestResults_Details_Websites_LikelyBlocked_Content_Paragraph, measurement.url.url, getString(measurement.getTestKeys().getWebsiteBlocking()))); + Markwon.setMarkdown(binding.desc, getString(R.string.TestResults_Details_Websites_LikelyBlocked_Content_Paragraph, measurement.url.url, getString(measurement.getTestKeys().getWebsiteBlocking()))); else - Markwon.setMarkdown(desc, getString(R.string.TestResults_Details_Websites_Reachable_Content_Paragraph, measurement.url.url)); - return v; + Markwon.setMarkdown(binding.desc, getString(R.string.TestResults_Details_Websites_Reachable_Content_Paragraph, measurement.url.url)); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/WhatsappFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/WhatsappFragment.java index 74cf5ce4d..e8e319940 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/WhatsappFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/measurement/WhatsappFragment.java @@ -4,26 +4,17 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentMeasurementWhatsappBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.jsonresult.TestKeys; -import butterknife.BindView; -import butterknife.ButterKnife; - public class WhatsappFragment extends Fragment { private static final String MEASUREMENT = "measurement"; - @BindView(R.id.desc) TextView desc; - @BindView(R.id.application) TextView application; - @BindView(R.id.webApp) TextView webApp; - @BindView(R.id.registrations) TextView registrations; public static WhatsappFragment newInstance(Measurement measurement) { Bundle args = new Bundle(); @@ -33,22 +24,23 @@ public static WhatsappFragment newInstance(Measurement measurement) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; Measurement measurement = (Measurement) getArguments().getSerializable(MEASUREMENT); assert measurement != null; - View v = inflater.inflate(R.layout.fragment_measurement_whatsapp, container, false); - ButterKnife.bind(this, v); - desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_InstantMessaging_WhatsApp_LikelyBlocked_Content_Paragraph : R.string.TestResults_Details_InstantMessaging_WhatsApp_Reachable_Content_Paragraph); - application.setText(measurement.getTestKeys().getWhatsappEndpointStatus()); + FragmentMeasurementWhatsappBinding binding = FragmentMeasurementWhatsappBinding.inflate(inflater,container,false); + binding.desc.setText(measurement.is_anomaly ? R.string.TestResults_Details_InstantMessaging_WhatsApp_LikelyBlocked_Content_Paragraph : R.string.TestResults_Details_InstantMessaging_WhatsApp_Reachable_Content_Paragraph); + binding.application.setText(measurement.getTestKeys().getWhatsappEndpointStatus()); if (TestKeys.BLOCKED.equals(measurement.getTestKeys().whatsapp_endpoints_status)) - application.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); - webApp.setText(measurement.getTestKeys().getWhatsappWebStatus()); + binding.application.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); + binding.webApp.setText(measurement.getTestKeys().getWhatsappWebStatus()); if (TestKeys.BLOCKED.equals(measurement.getTestKeys().whatsapp_web_status)) - webApp.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); - registrations.setText(measurement.getTestKeys().getWhatsappRegistrationStatus()); + binding.webApp.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); + binding.registrations.setText(measurement.getTestKeys().getWhatsappRegistrationStatus()); if (TestKeys.BLOCKED.equals(measurement.getTestKeys().registration_server_status)) - registrations.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); - return v; + binding.registrations.setTextColor(ContextCompat.getColor(getActivity(), R.color.color_yellow9)); + return binding.getRoot(); } } From 40013a38d58c41dd6bf7367143cf6fd7108f871e Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sun, 27 Aug 2023 08:07:04 +0100 Subject: [PATCH 23/33] Update `ResultDetailActivity` and component fragment to use `ViewBinding` --- .../activity/ResultDetailActivity.java | 57 ++++++------------- .../ooniprobe/item/MeasurementItem.java | 15 +++-- .../ooniprobe/item/MeasurementPerfItem.java | 49 +++++++--------- 3 files changed, 45 insertions(+), 76 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/ResultDetailActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/ResultDetailActivity.java index 15e334152..e80a6fafb 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/ResultDetailActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/ResultDetailActivity.java @@ -7,27 +7,23 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; - import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.widget.Toolbar; -import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager2.adapter.FragmentStateAdapter; -import androidx.viewpager2.widget.ViewPager2; - import com.google.android.material.snackbar.Snackbar; -import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayoutMediator; - +import localhost.toolkit.app.fragment.ConfirmDialogFragment; +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerAdapter; +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.PreferenceManager; import org.openobservatory.ooniprobe.common.ResubmitTask; +import org.openobservatory.ooniprobe.databinding.ActivityResultDetailBinding; import org.openobservatory.ooniprobe.domain.GetResults; import org.openobservatory.ooniprobe.domain.GetTestSuite; import org.openobservatory.ooniprobe.fragment.resultHeader.ResultHeaderDetailFragment; @@ -39,39 +35,18 @@ import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Network; import org.openobservatory.ooniprobe.model.database.Result; -import org.openobservatory.ooniprobe.test.suite.CircumventionSuite; -import org.openobservatory.ooniprobe.test.suite.ExperimentalSuite; -import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite; -import org.openobservatory.ooniprobe.test.suite.MiddleBoxesSuite; -import org.openobservatory.ooniprobe.test.suite.PerformanceSuite; -import org.openobservatory.ooniprobe.test.suite.WebsitesSuite; +import org.openobservatory.ooniprobe.test.suite.*; +import javax.inject.Inject; import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.app.fragment.ConfirmDialogFragment; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerAdapter; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - public class ResultDetailActivity extends AbstractActivity implements View.OnClickListener, ConfirmDialogFragment.OnConfirmedListener { private static final String ID = "id"; private static final String UPLOAD_KEY = "upload"; private static final String RERUN_KEY = "rerun"; - @BindView(R.id.coordinatorLayout) - CoordinatorLayout coordinatorLayout; - @BindView(R.id.toolbar) - Toolbar toolbar; - @BindView(R.id.tabLayout) - TabLayout tabLayout; - @BindView(R.id.pager) - ViewPager2 pager; - @BindView(R.id.recyclerView) - RecyclerView recycler; + private ArrayList items; private HeterogeneousRecyclerAdapter adapter; private Result result; @@ -97,27 +72,27 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { result = getResults.get(getIntent().getIntExtra(ID, 0)); assert result != null; setTheme(result.getTestSuite().getThemeLight()); - setContentView(R.layout.activity_result_detail); - ButterKnife.bind(this); - setSupportActionBar(toolbar); + ActivityResultDetailBinding binding = ActivityResultDetailBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + setSupportActionBar(binding.toolbar); ActionBar bar = getSupportActionBar(); if (bar != null) { bar.setDisplayHomeAsUpEnabled(true); bar.setTitle(result.getTestSuite().getTitle()); } - pager.setAdapter(new ResultHeaderAdapter(this)); - new TabLayoutMediator(tabLayout, pager, (tab, position) -> + binding.pager.setAdapter(new ResultHeaderAdapter(this)); + new TabLayoutMediator(binding.tabLayout, binding.pager, (tab, position) -> tab.setText("●") ).attach(); LinearLayoutManager layoutManager = new LinearLayoutManager(this); - recycler.setLayoutManager(layoutManager); - recycler.addItemDecoration(new DividerItemDecoration(this, layoutManager.getOrientation())); + binding.recyclerView.setLayoutManager(layoutManager); + binding.recyclerView.addItemDecoration(new DividerItemDecoration(this, layoutManager.getOrientation())); result.is_viewed = true; result.save(); items = new ArrayList<>(); adapter = new HeterogeneousRecyclerAdapter<>(this, items); - recycler.setAdapter(adapter); - snackbar = Snackbar.make(coordinatorLayout, R.string.Snackbar_ResultsSomeNotUploaded_Text, Snackbar.LENGTH_INDEFINITE) + binding.recyclerView.setAdapter(adapter); + snackbar = Snackbar.make(binding.coordinatorLayout, R.string.Snackbar_ResultsSomeNotUploaded_Text, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.Snackbar_ResultsSomeNotUploaded_UploadAll, v1 -> runAsyncTask()); } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/MeasurementItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/MeasurementItem.java index 570444b1a..fedfa4c6a 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/MeasurementItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/MeasurementItem.java @@ -11,12 +11,11 @@ import androidx.recyclerview.widget.RecyclerView; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemMeasurementBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.test.test.AbstractTest; import org.openobservatory.ooniprobe.test.test.WebConnectivity; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; public class MeasurementItem extends HeterogeneousRecyclerItem { @@ -28,7 +27,7 @@ public MeasurementItem(Measurement extra, View.OnClickListener onClickListener) } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_measurement, viewGroup, false)); + return new ViewHolder(ItemMeasurementBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { @@ -65,12 +64,12 @@ else if (extra.isUploaded()) } class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.text) TextView text; + TextView text; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - text.setOnClickListener(onClickListener); + ViewHolder(ItemMeasurementBinding binding) { + super(binding.getRoot()); + this.text = binding.text; + this.text.setOnClickListener(onClickListener); } } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/MeasurementPerfItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/MeasurementPerfItem.java index 5cffa6903..674f0a837 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/MeasurementPerfItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/MeasurementPerfItem.java @@ -4,19 +4,17 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemMeasurementPerfBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.test.test.Dash; import org.openobservatory.ooniprobe.test.test.HttpHeaderFieldManipulation; import org.openobservatory.ooniprobe.test.test.HttpInvalidRequestLine; import org.openobservatory.ooniprobe.test.test.Ndt; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; public class MeasurementPerfItem extends HeterogeneousRecyclerItem { @@ -28,46 +26,43 @@ public MeasurementPerfItem(Measurement extra, View.OnClickListener onClickListen } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_measurement_perf, viewGroup, false)); + return new ViewHolder(ItemMeasurementPerfBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { viewHolder.itemView.setTag(extra); - Context c = viewHolder.text.getContext(); + Context c = viewHolder.binding.text.getContext(); if (extra.getTest().getLabelResId() == (R.string.Test_Experimental_Fullname)) - viewHolder.text.setText(extra.getTest().getName()); + viewHolder.binding.text.setText(extra.getTest().getName()); else - viewHolder.text.setText(extra.getTest().getLabelResId()); - viewHolder.text.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, extra.is_failed || extra.isUploaded() ? 0 : R.drawable.cloudoff, 0); + viewHolder.binding.text.setText(extra.getTest().getLabelResId()); + viewHolder.binding.text.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, extra.is_failed || extra.isUploaded() ? 0 : R.drawable.cloudoff, 0); if (extra.test_name.equals(Dash.NAME)) { - viewHolder.data1.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.video_quality, 0, 0, 0); - viewHolder.data1.setText(extra.getTestKeys().getVideoQuality(true)); - viewHolder.data2.setVisibility(View.GONE); + viewHolder.binding.data1.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.video_quality, 0, 0, 0); + viewHolder.binding.data1.setText(extra.getTestKeys().getVideoQuality(true)); + viewHolder.binding.data2.setVisibility(View.GONE); } else if (extra.test_name.equals(Ndt.NAME)) { - viewHolder.data1.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.download_black, 0, 0, 0); - viewHolder.data1.setText(c.getString(R.string.twoParam, extra.getTestKeys().getDownload(c), c.getString(extra.getTestKeys().getDownloadUnit()))); - viewHolder.data2.setVisibility(View.VISIBLE); - viewHolder.data2.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.upload_black, 0, 0, 0); - viewHolder.data2.setText(c.getString(R.string.twoParam, extra.getTestKeys().getUpload(c), c.getString(extra.getTestKeys().getUploadUnit()))); + viewHolder.binding.data1.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.download_black, 0, 0, 0); + viewHolder.binding.data1.setText(c.getString(R.string.twoParam, extra.getTestKeys().getDownload(c), c.getString(extra.getTestKeys().getDownloadUnit()))); + viewHolder.binding.data2.setVisibility(View.VISIBLE); + viewHolder.binding.data2.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.upload_black, 0, 0, 0); + viewHolder.binding.data2.setText(c.getString(R.string.twoParam, extra.getTestKeys().getUpload(c), c.getString(extra.getTestKeys().getUploadUnit()))); } else if (extra.test_name.equals(HttpHeaderFieldManipulation.NAME) || extra.test_name.equals(HttpInvalidRequestLine.NAME)) { - viewHolder.data1.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.test_middle_boxes_small, 0, 0, 0); - viewHolder.data1.setText(extra.is_anomaly ? + viewHolder.binding.data1.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.test_middle_boxes_small, 0, 0, 0); + viewHolder.binding.data1.setText(extra.is_anomaly ? c.getString(R.string.TestResults_Overview_MiddleBoxes_Found) : c.getString(R.string.TestResults_Overview_MiddleBoxes_NotFound)); - viewHolder.data2.setVisibility(View.GONE); + viewHolder.binding.data2.setVisibility(View.GONE); } } class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.text) TextView text; - @BindView(R.id.data1) TextView data1; - @BindView(R.id.data2) TextView data2; - - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - itemView.setOnClickListener(onClickListener); + ItemMeasurementPerfBinding binding; + ViewHolder(ItemMeasurementPerfBinding binding) { + super(binding.getRoot()); + this.binding = binding; + binding.getRoot().setOnClickListener(onClickListener); } } } From 0f938bca9d01d6d172cbb377d316a8871c7886fe Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sun, 27 Aug 2023 08:31:41 +0100 Subject: [PATCH 24/33] Update `TextActivity` to `ViewBinding` --- .../ooniprobe/activity/TextActivity.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/TextActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/TextActivity.java index c13cc269d..94798e09a 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/TextActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/TextActivity.java @@ -7,24 +7,19 @@ import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; -import android.widget.TextView; import android.widget.Toast; - import androidx.annotation.Nullable; import androidx.fragment.app.FragmentManager; - +import localhost.toolkit.app.fragment.MessageDialogFragment; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.ReachabilityManager; +import org.openobservatory.ooniprobe.databinding.TextBinding; import org.openobservatory.ooniprobe.domain.MeasurementsManager; import org.openobservatory.ooniprobe.domain.callback.DomainCallback; import org.openobservatory.ooniprobe.model.database.Measurement; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.app.fragment.MessageDialogFragment; - public class TextActivity extends AbstractActivity { private Measurement measurement; private String text; @@ -34,8 +29,7 @@ public class TextActivity extends AbstractActivity { private static final String TEST = "test"; private static final String TYPE = "type"; private static final String TEXT = "text"; - @BindView(R.id.textView) - TextView textView; + private TextBinding binding; @Inject MeasurementsManager measurementsManager; @@ -52,8 +46,8 @@ public static Intent newIntent(Context context, int type, String text) { protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActivityComponent().inject(this); - setContentView(R.layout.text); - ButterKnife.bind(this); + binding = TextBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); showText(); } @@ -95,7 +89,7 @@ public void showText() { private void showLog() { try { text = measurementsManager.getReadableLog(measurement); - textView.setText(text); + binding.textView.setText(text); } catch (Exception e) { new MessageDialogFragment.Builder() .withTitle(getString(R.string.Modal_Error_LogNotFound)) @@ -107,7 +101,7 @@ private void showJson() { //Try to open file, if it doesn't exist dont show Error dialog immediately but try to download the json from internet try { text = measurementsManager.getReadableEntry(measurement); - textView.setText(text); + binding.textView.setText(text); } catch (Exception e) { e.printStackTrace(); if (ReachabilityManager.getNetworkType(this).equals(ReachabilityManager.NO_INTERNET)) { @@ -125,7 +119,7 @@ private void showJson() { public void onSuccess(String result) { runOnUiThread(() -> { text = result; - textView.setText(result); + binding.textView.setText(result); }); } @@ -140,7 +134,7 @@ public void onError(String msg) { } private void showUploadLog() { - textView.setText(text); + binding.textView.setText(text); } private void showError(String msg) { From d47ce050b0639c684605d2ded155a543e114cf5e Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sun, 27 Aug 2023 08:49:57 +0100 Subject: [PATCH 25/33] Update `ProgressFragment` to `ViewBinding` --- .../ooniprobe/fragment/ProgressFragment.java | 71 +++++++------------ 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/ProgressFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/ProgressFragment.java index a4f948a15..b37840428 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/ProgressFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/ProgressFragment.java @@ -5,50 +5,35 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; - -import androidx.core.app.ActivityCompat; -import androidx.fragment.app.Fragment; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; - import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - +import androidx.core.app.ActivityCompat; +import androidx.fragment.app.Fragment; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.activity.RunningActivity; import org.openobservatory.ooniprobe.common.Application; import org.openobservatory.ooniprobe.common.PreferenceManager; import org.openobservatory.ooniprobe.common.TestProgressRepository; import org.openobservatory.ooniprobe.common.service.RunTestService; +import org.openobservatory.ooniprobe.databinding.FragmentProgressBinding; import org.openobservatory.ooniprobe.receiver.TestRunBroadRequestReceiver; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; - /** * Monitors and displays progress of {@link RunTestService}. */ public class ProgressFragment extends Fragment { private TestRunBroadRequestReceiver receiver; + private FragmentProgressBinding biding; + @Inject PreferenceManager preferenceManager; @Inject TestProgressRepository testProgressRepository; - @BindView(R.id.progress_layout) - FrameLayout progress_layout; - @BindView(R.id.progress) - ProgressBar progress; - @BindView(R.id.running) - TextView running; - @BindView(R.id.name) - TextView name; public ProgressFragment() { // Required empty public constructor @@ -62,24 +47,18 @@ public void onCreate(Bundle savedInstanceState) { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_progress, container, false); - ButterKnife.bind(this, v); + biding = FragmentProgressBinding.inflate(inflater, container, false); ((Application) getActivity().getApplication()).getFragmentComponent().inject(this); - v.setOnTouchListener(new View.OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - if(event.getAction() == MotionEvent.ACTION_DOWN){ - Intent intent = new Intent(getContext(), RunningActivity.class); - ActivityCompat.startActivity(getActivity(), intent, null); - } - return true; - } + biding.getRoot().setOnClickListener(v -> { + Intent intent = new Intent(getContext(), RunningActivity.class); + ActivityCompat.startActivity(getActivity(), intent, null); }); testProgressRepository.getProgress().observe(getViewLifecycleOwner(),progressValue -> { if (progressValue!=null) { - progress.setProgress(progressValue); + biding.progress.setProgress(progressValue); } }); - return v; + return biding.getRoot(); } @Override @@ -97,10 +76,10 @@ public void bindTestService() { if (activity!=null && ((Application)activity.getApplication()).isTestRunning()) { Intent intent = new Intent(getActivity(), RunTestService.class); getActivity().bindService(intent, receiver, Context.BIND_AUTO_CREATE); - progress_layout.setVisibility(View.VISIBLE); + biding.progressLayout.setVisibility(View.VISIBLE); } else - progress_layout.setVisibility(View.GONE); + biding.progressLayout.setVisibility(View.GONE); } private void updateUI(RunTestService service){ @@ -109,15 +88,15 @@ private void updateUI(RunTestService service){ Integer progressLevel = testProgressRepository.getProgress().getValue(); if (progressLevel != null) { - progress.setProgress(progressLevel); + biding.progress.setProgress(progressLevel); } else { - progress.setIndeterminate(true); + biding.progress.setIndeterminate(true); } if (service != null && service.task != null){ if (service.task.currentSuite != null) - progress.setMax(service.task.getMax(preferenceManager)); + biding.progress.setMax(service.task.getMax(preferenceManager)); if (service.task.currentTest != null) - name.setText(getString(service.task.currentTest.getLabelResId())); + biding.name.setText(getString(service.task.currentTest.getLabelResId())); } } } @@ -146,15 +125,15 @@ public void onStart(RunTestService service) { @Override public void onRun(String value) { - name.setText(value); + biding.name.setText(value); } @Override public void onProgress(int state, double eta) { - if (progress.isIndeterminate()) + if (biding.progress.isIndeterminate()) updateUI(receiver.service); - progress.setIndeterminate(false); - progress.setProgress(state); + biding.progress.setIndeterminate(false); + biding.progress.setProgress(state); } @Override @@ -169,17 +148,17 @@ public void onError(String value) { @Override public void onUrl() { - progress.setIndeterminate(false); + biding.progress.setIndeterminate(false); } @Override public void onInterrupt() { - running.setText(getString(R.string.Dashboard_Running_Stopping_Title)); + biding.running.setText(getString(R.string.Dashboard_Running_Stopping_Title)); } @Override public void onEnd(Context context) { - progress_layout.setVisibility(View.GONE); + biding.progressLayout.setVisibility(View.GONE); } } } \ No newline at end of file From 06f9735d3efb88d0e71348a11074d5bbd967f67f Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sun, 27 Aug 2023 10:14:42 +0100 Subject: [PATCH 26/33] Update `ResultListFragment` and components to `ViewBinding` --- .../fragment/ResultListFragment.java | 113 +++++++----------- .../ooniprobe/item/CircumventionItem.java | 43 +++---- .../ooniprobe/item/ExperimentalItem.java | 28 ++--- .../ooniprobe/item/InstantMessagingItem.java | 38 +++--- .../ooniprobe/item/MiddleboxesItem.java | 47 ++++---- .../ooniprobe/item/PerformanceItem.java | 43 +++---- .../ooniprobe/item/WebsiteItem.java | 44 +++---- 7 files changed, 139 insertions(+), 217 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/ResultListFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/ResultListFragment.java index c0835739d..8b881c25e 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/ResultListFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/ResultListFragment.java @@ -3,30 +3,21 @@ import android.app.ProgressDialog; import android.content.DialogInterface; import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Spinner; -import android.widget.TextView; - +import android.view.*; +import android.widget.AdapterView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - import com.google.android.material.snackbar.Snackbar; import com.raizlabs.android.dbflow.sql.language.Method; import com.raizlabs.android.dbflow.sql.language.SQLite; - +import localhost.toolkit.app.fragment.ConfirmDialogFragment; +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerAdapter; +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.activity.AbstractActivity; import org.openobservatory.ooniprobe.activity.ResultDetailActivity; @@ -34,60 +25,25 @@ import org.openobservatory.ooniprobe.common.Application; import org.openobservatory.ooniprobe.common.PreferenceManager; import org.openobservatory.ooniprobe.common.ResubmitTask; +import org.openobservatory.ooniprobe.databinding.FragmentResultListBinding; import org.openobservatory.ooniprobe.domain.GetResults; import org.openobservatory.ooniprobe.domain.MeasurementsManager; import org.openobservatory.ooniprobe.domain.models.DatedResults; -import org.openobservatory.ooniprobe.item.CircumventionItem; -import org.openobservatory.ooniprobe.item.DateItem; -import org.openobservatory.ooniprobe.item.ExperimentalItem; -import org.openobservatory.ooniprobe.item.FailedItem; -import org.openobservatory.ooniprobe.item.InstantMessagingItem; -import org.openobservatory.ooniprobe.item.MiddleboxesItem; -import org.openobservatory.ooniprobe.item.PerformanceItem; -import org.openobservatory.ooniprobe.item.WebsiteItem; +import org.openobservatory.ooniprobe.item.*; import org.openobservatory.ooniprobe.model.database.Network; import org.openobservatory.ooniprobe.model.database.Result; import org.openobservatory.ooniprobe.model.database.Result_Table; -import org.openobservatory.ooniprobe.test.suite.CircumventionSuite; -import org.openobservatory.ooniprobe.test.suite.ExperimentalSuite; -import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite; -import org.openobservatory.ooniprobe.test.suite.MiddleBoxesSuite; -import org.openobservatory.ooniprobe.test.suite.PerformanceSuite; -import org.openobservatory.ooniprobe.test.suite.WebsitesSuite; +import org.openobservatory.ooniprobe.test.suite.*; +import javax.inject.Inject; import java.io.Serializable; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnItemSelected; -import localhost.toolkit.app.fragment.ConfirmDialogFragment; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerAdapter; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - public class ResultListFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener, ConfirmDialogFragment.OnConfirmedListener { - @BindView(R.id.coordinatorLayout) - CoordinatorLayout coordinatorLayout; - @BindView(R.id.toolbar) - Toolbar toolbar; - @BindView(R.id.tests) - TextView tests; - @BindView(R.id.networks) - TextView networks; - @BindView(R.id.upload) - TextView upload; - @BindView(R.id.download) - TextView download; - @BindView(R.id.filterTests) - Spinner filterTests; - @BindView(R.id.recycler) - RecyclerView recycler; - @BindView(R.id.emptyState) - TextView emptyState; + private FragmentResultListBinding binding; + private ArrayList items; private HeterogeneousRecyclerAdapter adapter; private boolean refresh; @@ -105,20 +61,32 @@ public class ResultListFragment extends Fragment implements View.OnClickListener @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_result_list, container, false); - ButterKnife.bind(this, v); + binding = FragmentResultListBinding.inflate(inflater, container, false); ((Application) getActivity().getApplication()).getFragmentComponent().inject(this); - ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar); + ((AppCompatActivity) getActivity()).setSupportActionBar(binding.toolbar); setHasOptionsMenu(true); getActivity().setTitle(R.string.TestResults_Overview_Title); reloadHeader(); LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); - recycler.setLayoutManager(layoutManager); - recycler.addItemDecoration(new DividerItemDecoration(getActivity(), layoutManager.getOrientation())); + binding.recycler.setLayoutManager(layoutManager); + binding.recycler.addItemDecoration(new DividerItemDecoration(getActivity(), layoutManager.getOrientation())); items = new ArrayList<>(); adapter = new HeterogeneousRecyclerAdapter<>(getActivity(), items); - recycler.setAdapter(adapter); - snackbar = Snackbar.make(coordinatorLayout, R.string.Snackbar_ResultsSomeNotUploaded_Text, Snackbar.LENGTH_INDEFINITE) + binding.recycler.setAdapter(adapter); + + binding.filterTests.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + queryList(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + queryList(); + } + }); + + snackbar = Snackbar.make(binding.coordinatorLayout, R.string.Snackbar_ResultsSomeNotUploaded_Text, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.Snackbar_ResultsSomeNotUploaded_UploadAll, v1 -> new ConfirmDialogFragment.Builder() .withExtra(R.string.Modal_ResultsNotUploaded_Title) @@ -127,14 +95,14 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c .withPositiveButton(getString(R.string.Modal_ResultsNotUploaded_Button_Upload)) .build().show(getChildFragmentManager(), null) ); - return v; + return binding.getRoot(); } public void reloadHeader() { - tests.setText(getString(R.string.d, SQLite.selectCountOf().from(Result.class).longValue())); - networks.setText(getString(R.string.d, SQLite.selectCountOf().from(Network.class).longValue())); - upload.setText(Result.readableFileSize(SQLite.select(Method.sum(Result_Table.data_usage_up)).from(Result.class).longValue())); - download.setText(Result.readableFileSize(SQLite.select(Method.sum(Result_Table.data_usage_down)).from(Result.class).longValue())); + binding.tests.setText(getString(R.string.d, SQLite.selectCountOf().from(Result.class).longValue())); + binding.networks.setText(getString(R.string.d, SQLite.selectCountOf().from(Network.class).longValue())); + binding.upload.setText(Result.readableFileSize(SQLite.select(Method.sum(Result_Table.data_usage_up)).from(Result.class).longValue())); + binding.download.setText(Result.readableFileSize(SQLite.select(Method.sum(Result_Table.data_usage_down)).from(Result.class).longValue())); } @Override @@ -173,7 +141,6 @@ public boolean onOptionsItemSelected(MenuItem item) { } } - @OnItemSelected(R.id.filterTests) void queryList() { if (measurementsManager.hasUploadables()) { snackbar.show(); @@ -183,15 +150,15 @@ void queryList() { items.clear(); - String filter = getResources().getStringArray(R.array.filterTestValues)[filterTests.getSelectedItemPosition()]; + String filter = getResources().getStringArray(R.array.filterTestValues)[binding.filterTests.getSelectedItemPosition()]; List list = getResults.getGroupedByMonth(filter); if (list.isEmpty()) { - emptyState.setVisibility(View.VISIBLE); - recycler.setVisibility(View.GONE); + binding.emptyState.setVisibility(View.VISIBLE); + binding.recycler.setVisibility(View.GONE); } else { - emptyState.setVisibility(View.GONE); - recycler.setVisibility(View.VISIBLE); + binding.emptyState.setVisibility(View.GONE); + binding.recycler.setVisibility(View.VISIBLE); for (DatedResults group : list) { items.add(new DateItem(group.getGroupedDate())); for (Result result : group.getResultsList()) { diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/CircumventionItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/CircumventionItem.java index f4e8fbc6e..2d54bc237 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/CircumventionItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/CircumventionItem.java @@ -4,23 +4,18 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; import androidx.recyclerview.widget.RecyclerView; - +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemCircumventionBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Network; import org.openobservatory.ooniprobe.model.database.Result; import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - public class CircumventionItem extends HeterogeneousRecyclerItem { private final View.OnClickListener onClickListener; private final View.OnLongClickListener onLongClickListener; @@ -31,39 +26,35 @@ public CircumventionItem(Result extra, View.OnClickListener onClickListener, Vie this.onLongClickListener = onLongClickListener; } - @Override public CircumventionItem.ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new CircumventionItem.ViewHolder(layoutInflater.inflate(R.layout.item_circumvention, viewGroup, false)); + @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { + return new ViewHolder(ItemCircumventionBinding.inflate(layoutInflater, viewGroup, false)); } - @Override public void onBindViewHolder(CircumventionItem.ViewHolder viewHolder) { + @Override public void onBindViewHolder(ViewHolder viewHolder) { viewHolder.itemView.setTag(extra); viewHolder.itemView.setOnClickListener(onClickListener); viewHolder.itemView.setOnLongClickListener(onLongClickListener); viewHolder.itemView.setBackgroundColor(ContextCompat.getColor(viewHolder.itemView.getContext(), extra.is_viewed ? android.R.color.transparent : R.color.color_yellow0)); - viewHolder.asnName.setText(Network.toString(viewHolder.asnName.getContext(), extra.network)); - viewHolder.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); + viewHolder.binding.asnName.setText(Network.toString(viewHolder.binding.asnName.getContext(), extra.network)); + viewHolder.binding.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); Long blocked = extra.countAnomalousMeasurements(); Long available = extra.countOkMeasurements(); - viewHolder.failedMeasurements.setText(viewHolder.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_Circumvention_Blocked, blocked.intValue(), blocked.toString())); - viewHolder.okMeasurements.setText(viewHolder.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_Circumvention_Available, available.intValue(), available.toString())); - viewHolder.failedMeasurements.setTextColor(ContextCompat.getColor(viewHolder.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); - DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.failedMeasurements.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); + viewHolder.binding.failedMeasurements.setText(viewHolder.binding.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_Circumvention_Blocked, blocked.intValue(), blocked.toString())); + viewHolder.binding.okMeasurements.setText(viewHolder.binding.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_Circumvention_Available, available.intValue(), available.toString())); + viewHolder.binding.failedMeasurements.setTextColor(ContextCompat.getColor(viewHolder.binding.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); + DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.binding.failedMeasurements.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.binding.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); boolean allUploaded = true; for (Measurement m : extra.getMeasurements()) allUploaded = allUploaded && (m.isUploaded() || m.is_failed); - viewHolder.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); + viewHolder.binding.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); } - class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.asnName) - TextView asnName; - @BindView(R.id.startTime) TextView startTime; - @BindView(R.id.failedMeasurements) TextView failedMeasurements; - @BindView(R.id.okMeasurements) TextView okMeasurements; + public static class ViewHolder extends RecyclerView.ViewHolder { + ItemCircumventionBinding binding; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolder(ItemCircumventionBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/ExperimentalItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/ExperimentalItem.java index d3df87b6e..c4f9688b5 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/ExperimentalItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/ExperimentalItem.java @@ -4,22 +4,17 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; - +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemExperimentalBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Network; import org.openobservatory.ooniprobe.model.database.Result; import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - public class ExperimentalItem extends HeterogeneousRecyclerItem { private final View.OnClickListener onClickListener; private final View.OnLongClickListener onLongClickListener; @@ -31,7 +26,7 @@ public ExperimentalItem(Result extra, View.OnClickListener onClickListener, View } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_experimental, viewGroup, false)); + return new ViewHolder(ItemExperimentalBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { @@ -39,21 +34,20 @@ public ExperimentalItem(Result extra, View.OnClickListener onClickListener, View viewHolder.itemView.setOnClickListener(onClickListener); viewHolder.itemView.setOnLongClickListener(onLongClickListener); viewHolder.itemView.setBackgroundColor(ContextCompat.getColor(viewHolder.itemView.getContext(), extra.is_viewed ? android.R.color.transparent : R.color.color_yellow0)); - viewHolder.asnName.setText(Network.toString(viewHolder.asnName.getContext(), extra.network)); - viewHolder.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); + viewHolder.binding.asnName.setText(Network.toString(viewHolder.binding.asnName.getContext(), extra.network)); + viewHolder.binding.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); boolean allUploaded = true; for (Measurement m : extra.getMeasurements()) allUploaded = allUploaded && (m.isUploaded() || m.is_failed); - viewHolder.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); + viewHolder.binding.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); } - class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.asnName) TextView asnName; - @BindView(R.id.startTime) TextView startTime; + public static class ViewHolder extends RecyclerView.ViewHolder { + ItemExperimentalBinding binding; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolder(ItemExperimentalBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/InstantMessagingItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/InstantMessagingItem.java index 86fab7fa5..799a7fc3d 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/InstantMessagingItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/InstantMessagingItem.java @@ -4,23 +4,18 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; import androidx.recyclerview.widget.RecyclerView; - +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemInstantmessagingBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Network; import org.openobservatory.ooniprobe.model.database.Result; import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - public class InstantMessagingItem extends HeterogeneousRecyclerItem { private final View.OnClickListener onClickListener; private final View.OnLongClickListener onLongClickListener; @@ -32,7 +27,7 @@ public InstantMessagingItem(Result extra, View.OnClickListener onClickListener, } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_instantmessaging, viewGroup, false)); + return new ViewHolder(ItemInstantmessagingBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { @@ -40,29 +35,26 @@ public InstantMessagingItem(Result extra, View.OnClickListener onClickListener, viewHolder.itemView.setOnClickListener(onClickListener); viewHolder.itemView.setOnLongClickListener(onLongClickListener); viewHolder.itemView.setBackgroundColor(ContextCompat.getColor(viewHolder.itemView.getContext(), extra.is_viewed ? android.R.color.transparent : R.color.color_yellow0)); - viewHolder.asnName.setText(Network.toString(viewHolder.asnName.getContext(), extra.network)); - viewHolder.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); + viewHolder.binding.asnName.setText(Network.toString(viewHolder.binding.asnName.getContext(), extra.network)); + viewHolder.binding.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); Long blocked = extra.countAnomalousMeasurements(); Long available = extra.countOkMeasurements(); - viewHolder.failedMeasurements.setText(viewHolder.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_InstantMessaging_Blocked, blocked.intValue(), blocked.toString())); - viewHolder.okMeasurements.setText(viewHolder.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_InstantMessaging_Available, available.intValue(), available.toString())); - viewHolder.failedMeasurements.setTextColor(ContextCompat.getColor(viewHolder.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); - DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.failedMeasurements.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); + viewHolder.binding.failedMeasurements.setText(viewHolder.binding.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_InstantMessaging_Blocked, blocked.intValue(), blocked.toString())); + viewHolder.binding.okMeasurements.setText(viewHolder.binding.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_InstantMessaging_Available, available.intValue(), available.toString())); + viewHolder.binding.failedMeasurements.setTextColor(ContextCompat.getColor(viewHolder.binding.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); + DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.binding.failedMeasurements.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.binding.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); boolean allUploaded = true; for (Measurement m : extra.getMeasurements()) allUploaded = allUploaded && (m.isUploaded() || m.is_failed); - viewHolder.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); + viewHolder.binding.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); } - class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.asnName) TextView asnName; - @BindView(R.id.startTime) TextView startTime; - @BindView(R.id.failedMeasurements) TextView failedMeasurements; - @BindView(R.id.okMeasurements) TextView okMeasurements; + public static class ViewHolder extends RecyclerView.ViewHolder { + ItemInstantmessagingBinding binding; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolder(ItemInstantmessagingBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/MiddleboxesItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/MiddleboxesItem.java index f776347cb..df9aeefc8 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/MiddleboxesItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/MiddleboxesItem.java @@ -4,23 +4,18 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; import androidx.recyclerview.widget.RecyclerView; - +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemMiddleboxesBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Network; import org.openobservatory.ooniprobe.model.database.Result; import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - /** * @deprecated * It is not possible to run a MiddleBoxesSuite anymore @@ -38,7 +33,7 @@ public MiddleboxesItem(Result extra, View.OnClickListener onClickListener, View. } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_middleboxes, viewGroup, false)); + return new ViewHolder(ItemMiddleboxesBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { @@ -46,35 +41,33 @@ public MiddleboxesItem(Result extra, View.OnClickListener onClickListener, View. viewHolder.itemView.setOnClickListener(onClickListener); viewHolder.itemView.setOnLongClickListener(onLongClickListener); viewHolder.itemView.setBackgroundColor(ContextCompat.getColor(viewHolder.itemView.getContext(), extra.is_viewed ? android.R.color.transparent : R.color.color_yellow0)); - viewHolder.asnName.setText(Network.toString(viewHolder.asnName.getContext(), extra.network)); - viewHolder.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); + viewHolder.binding.asnName.setText(Network.toString(viewHolder.binding.asnName.getContext(), extra.network)); + viewHolder.binding.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); if (extra.countAnomalousMeasurements() > 0) { - viewHolder.status.setText(R.string.TestResults_Overview_MiddleBoxes_Found); - viewHolder.status.setTextColor(ContextCompat.getColor(viewHolder.status.getContext(), R.color.color_yellow9)); - DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.status.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.status.getContext(), R.color.color_yellow9)); + viewHolder.binding.status.setText(R.string.TestResults_Overview_MiddleBoxes_Found); + viewHolder.binding.status.setTextColor(ContextCompat.getColor(viewHolder.binding.status.getContext(), R.color.color_yellow9)); + DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.binding.status.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.binding.status.getContext(), R.color.color_yellow9)); } else if (extra.countCompletedMeasurements() == 0) { - viewHolder.status.setText(R.string.TestResults_Overview_MiddleBoxes_Failed); - viewHolder.status.setTextColor(ContextCompat.getColor(viewHolder.status.getContext(), R.color.color_gray9)); - DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.status.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.status.getContext(), R.color.color_gray9)); + viewHolder.binding.status.setText(R.string.TestResults_Overview_MiddleBoxes_Failed); + viewHolder.binding.status.setTextColor(ContextCompat.getColor(viewHolder.binding.status.getContext(), R.color.color_gray9)); + DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.binding.status.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.binding.status.getContext(), R.color.color_gray9)); } else { - viewHolder.status.setText(R.string.TestResults_Overview_MiddleBoxes_NotFound); - viewHolder.status.setTextColor(ContextCompat.getColor(viewHolder.status.getContext(), R.color.color_gray9)); - DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.status.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.status.getContext(), R.color.color_gray9)); + viewHolder.binding.status.setText(R.string.TestResults_Overview_MiddleBoxes_NotFound); + viewHolder.binding.status.setTextColor(ContextCompat.getColor(viewHolder.binding.status.getContext(), R.color.color_gray9)); + DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.binding.status.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.binding.status.getContext(), R.color.color_gray9)); } boolean allUploaded = true; for (Measurement m : extra.getMeasurements()) allUploaded = allUploaded && (m.isUploaded() || m.is_failed); - viewHolder.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); + viewHolder.binding.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); } - class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.asnName) TextView asnName; - @BindView(R.id.startTime) TextView startTime; - @BindView(R.id.status) TextView status; + public static class ViewHolder extends RecyclerView.ViewHolder { + ItemMiddleboxesBinding binding; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolder(ItemMiddleboxesBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/PerformanceItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/PerformanceItem.java index af9d6dff2..ac29d1292 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/PerformanceItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/PerformanceItem.java @@ -5,12 +5,11 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; - +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemPerformanceBinding; import org.openobservatory.ooniprobe.fragment.resultHeader.ResultHeaderPerformanceFragment; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Network; @@ -20,10 +19,6 @@ import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - public class PerformanceItem extends HeterogeneousRecyclerItem { private final View.OnClickListener onClickListener; private final View.OnLongClickListener onLongClickListener; @@ -35,7 +30,7 @@ public PerformanceItem(Result extra, View.OnClickListener onClickListener, View. } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_performance, viewGroup, false)); + return new ViewHolder(ItemPerformanceBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { @@ -44,32 +39,28 @@ public PerformanceItem(Result extra, View.OnClickListener onClickListener, View. viewHolder.itemView.setOnClickListener(onClickListener); viewHolder.itemView.setOnLongClickListener(onLongClickListener); viewHolder.itemView.setBackgroundColor(ContextCompat.getColor(c, extra.is_viewed ? android.R.color.transparent : R.color.color_yellow0)); - viewHolder.asnName.setText(Network.toString(viewHolder.asnName.getContext(), extra.network)); - viewHolder.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); + viewHolder.binding.asnName.setText(Network.toString(viewHolder.binding.asnName.getContext(), extra.network)); + viewHolder.binding.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); Measurement dashM = extra.getMeasurement(Dash.NAME); Measurement ndtM = extra.getMeasurement(Ndt.NAME); - viewHolder.quality.setText(dashM == null ? R.string.TestResults_NotAvailable : dashM.getTestKeys().getVideoQuality(false)); - viewHolder.upload.setText(ndtM == null ? c.getString(R.string.TestResults_NotAvailable) : c.getString(R.string.twoParam, ndtM.getTestKeys().getUpload(c), c.getString(ndtM.getTestKeys().getUploadUnit()))); - viewHolder.download.setText(ndtM == null ? c.getString(R.string.TestResults_NotAvailable) : c.getString(R.string.twoParam, ndtM.getTestKeys().getDownload(c), c.getString(ndtM.getTestKeys().getDownloadUnit()))); - viewHolder.quality.setAlpha(dashM == null ? ResultHeaderPerformanceFragment.ALPHA_DIS : ResultHeaderPerformanceFragment.ALPHA_ENA); - viewHolder.upload.setAlpha(ndtM == null ? ResultHeaderPerformanceFragment.ALPHA_DIS : ResultHeaderPerformanceFragment.ALPHA_ENA); - viewHolder.download.setAlpha(ndtM == null ? ResultHeaderPerformanceFragment.ALPHA_DIS : ResultHeaderPerformanceFragment.ALPHA_ENA); + viewHolder.binding.quality.setText(dashM == null ? R.string.TestResults_NotAvailable : dashM.getTestKeys().getVideoQuality(false)); + viewHolder.binding.upload.setText(ndtM == null ? c.getString(R.string.TestResults_NotAvailable) : c.getString(R.string.twoParam, ndtM.getTestKeys().getUpload(c), c.getString(ndtM.getTestKeys().getUploadUnit()))); + viewHolder.binding.download.setText(ndtM == null ? c.getString(R.string.TestResults_NotAvailable) : c.getString(R.string.twoParam, ndtM.getTestKeys().getDownload(c), c.getString(ndtM.getTestKeys().getDownloadUnit()))); + viewHolder.binding.quality.setAlpha(dashM == null ? ResultHeaderPerformanceFragment.ALPHA_DIS : ResultHeaderPerformanceFragment.ALPHA_ENA); + viewHolder.binding.upload.setAlpha(ndtM == null ? ResultHeaderPerformanceFragment.ALPHA_DIS : ResultHeaderPerformanceFragment.ALPHA_ENA); + viewHolder.binding.download.setAlpha(ndtM == null ? ResultHeaderPerformanceFragment.ALPHA_DIS : ResultHeaderPerformanceFragment.ALPHA_ENA); boolean allUploaded = true; for (Measurement m : extra.getMeasurements()) allUploaded = allUploaded && (m.isUploaded() || m.is_failed); - viewHolder.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); + viewHolder.binding.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); } - class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.asnName) TextView asnName; - @BindView(R.id.startTime) TextView startTime; - @BindView(R.id.upload) TextView upload; - @BindView(R.id.download) TextView download; - @BindView(R.id.quality) TextView quality; + public static class ViewHolder extends RecyclerView.ViewHolder { + ItemPerformanceBinding binding; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolder(ItemPerformanceBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/WebsiteItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/WebsiteItem.java index 572f00c24..60d9f0589 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/WebsiteItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/WebsiteItem.java @@ -4,23 +4,18 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; import androidx.recyclerview.widget.RecyclerView; - +import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemWebsitesBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Network; import org.openobservatory.ooniprobe.model.database.Result; import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; -import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; - public class WebsiteItem extends HeterogeneousRecyclerItem { private final View.OnClickListener onClickListener; private final View.OnLongClickListener onLongClickListener; @@ -31,38 +26,37 @@ public WebsiteItem(Result extra, View.OnClickListener onClickListener, View.OnLo this.onLongClickListener = onLongClickListener; } - @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_websites, viewGroup, false)); + @Override + public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { + return new ViewHolder(ItemWebsitesBinding.inflate(layoutInflater, viewGroup, false)); } - @Override public void onBindViewHolder(ViewHolder viewHolder) { + @Override + public void onBindViewHolder(ViewHolder viewHolder) { viewHolder.itemView.setTag(extra); viewHolder.itemView.setOnClickListener(onClickListener); viewHolder.itemView.setOnLongClickListener(onLongClickListener); viewHolder.itemView.setBackgroundColor(ContextCompat.getColor(viewHolder.itemView.getContext(), extra.is_viewed ? android.R.color.transparent : R.color.color_yellow0)); - viewHolder.asnName.setText(Network.toString(viewHolder.asnName.getContext(), extra.network)); - viewHolder.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); + viewHolder.binding.asnName.setText(Network.toString(viewHolder.binding.asnName.getContext(), extra.network)); + viewHolder.binding.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); Long blocked = extra.countAnomalousMeasurements(); Long tested = extra.countTotalMeasurements(); - viewHolder.failedMeasurements.setText(viewHolder.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_Websites_Blocked, blocked.intValue(), blocked.toString())); - viewHolder.testedMeasurements.setText(viewHolder.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_Websites_Tested, tested.intValue(), tested.toString())); - viewHolder.failedMeasurements.setTextColor(ContextCompat.getColor(viewHolder.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); - DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.failedMeasurements.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); + viewHolder.binding.failedMeasurements.setText(viewHolder.binding.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_Websites_Blocked, blocked.intValue(), blocked.toString())); + viewHolder.binding.testedMeasurements.setText(viewHolder.binding.failedMeasurements.getContext().getResources().getQuantityString(R.plurals.TestResults_Overview_Websites_Tested, tested.intValue(), tested.toString())); + viewHolder.binding.failedMeasurements.setTextColor(ContextCompat.getColor(viewHolder.binding.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); + DrawableCompat.setTint(DrawableCompat.wrap(viewHolder.binding.failedMeasurements.getCompoundDrawablesRelative()[0]).mutate(), ContextCompat.getColor(viewHolder.binding.failedMeasurements.getContext(), blocked == 0 ? R.color.color_gray9 : R.color.color_yellow9)); boolean allUploaded = true; for (Measurement m : extra.getMeasurements()) allUploaded = allUploaded && (m.isUploaded() || m.is_failed); - viewHolder.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); + viewHolder.binding.startTime.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, allUploaded ? 0 : R.drawable.cloudoff, 0); } - class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.asnName) TextView asnName; - @BindView(R.id.startTime) TextView startTime; - @BindView(R.id.failedMeasurements) TextView failedMeasurements; - @BindView(R.id.testedMeasurements) TextView testedMeasurements; + public static class ViewHolder extends RecyclerView.ViewHolder { + ItemWebsitesBinding binding; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolder(ItemWebsitesBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } \ No newline at end of file From 1b8d017ff72633083697340d3e8e4b3f6820d498 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sun, 27 Aug 2023 10:39:20 +0100 Subject: [PATCH 27/33] Updated result header fragments to `ViewBinding` --- .../ResultHeaderDetailFragment.java | 62 ++++++++---------- .../ResultHeaderMiddleboxFragment.java | 30 +++++---- .../ResultHeaderPerformanceFragment.java | 64 +++++++------------ .../resultHeader/ResultHeaderTBAFragment.java | 34 ++++------ 4 files changed, 78 insertions(+), 112 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderDetailFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderDetailFragment.java index 45331eb23..4f9130576 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderDetailFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderDetailFragment.java @@ -5,23 +5,17 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.view.ContextThemeWrapper; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentResultHeadDetailBinding; import org.openobservatory.ooniprobe.model.database.Network; import java.util.Date; import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; - public class ResultHeaderDetailFragment extends Fragment { private static final String NETWORK = "network"; private static final String COUNTRY_CODE = "country_code"; @@ -31,19 +25,6 @@ public class ResultHeaderDetailFragment extends Fragment { private static final String START_TIME = "start_time"; private static final String IS_TOTAL_RUNTIME = "isTotalRuntime"; private static final String LIGHT_THEME = "lightTheme"; - @BindView(R.id.dataUsage) LinearLayout dataUsage; - @BindView(R.id.startTimeBox) LinearLayout startTimeBox; - @BindView(R.id.runtimeBox) LinearLayout runtimeBox; - @BindView(R.id.countryBox) LinearLayout countryBox; - @BindView(R.id.networkBox) LinearLayout networkBox; - @BindView(R.id.startTime) TextView startTime; - @BindView(R.id.upload) TextView upload; - @BindView(R.id.download) TextView download; - @BindView(R.id.runtime) TextView runtime; - @BindView(R.id.runtimeLabel) TextView runtimeLabel; - @BindView(R.id.country) TextView country; - @BindView(R.id.networkName) TextView networkName; - @BindView(R.id.networkDetail) TextView networkDetail; public static ResultHeaderDetailFragment newInstance(boolean lightTheme, String data_usage_up, String data_usage_down, Date start_time, Double runtime, Boolean isTotalRuntime, String country_code, Network network) { Bundle args = new Bundle(); @@ -67,35 +48,42 @@ public static ResultHeaderDetailFragment newInstance(boolean lightTheme, String return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; int themeResId = getArguments().getBoolean(LIGHT_THEME) ? R.style.Theme_MaterialComponents_Light_NoActionBar_App : R.style.Theme_MaterialComponents_NoActionBar_App; - View v = inflater.cloneInContext(new ContextThemeWrapper(getActivity(), themeResId)).inflate(R.layout.fragment_result_head_detail, container, false); - ButterKnife.bind(this, v); + FragmentResultHeadDetailBinding binding = FragmentResultHeadDetailBinding.inflate(inflater.cloneInContext(new ContextThemeWrapper(getActivity(), themeResId)), container, false); if (getArguments().containsKey(DATA_USAGE_DOWN) && getArguments().containsKey(DATA_USAGE_UP)) { - download.setText(getArguments().getString(DATA_USAGE_DOWN)); - upload.setText(getArguments().getString(DATA_USAGE_UP)); + binding.download.setText(getArguments().getString(DATA_USAGE_DOWN)); + binding.upload.setText(getArguments().getString(DATA_USAGE_UP)); } else - dataUsage.setVisibility(View.GONE); + binding.dataUsage.setVisibility(View.GONE); if (getArguments().containsKey(START_TIME)) - startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), (Date) getArguments().getSerializable(START_TIME))); + binding.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), (Date) getArguments().getSerializable(START_TIME))); else - startTimeBox.setVisibility(View.GONE); + binding.startTimeBox.setVisibility(View.GONE); if (getArguments().containsKey(RUNTIME)) { - runtime.setText(getString(R.string.f, getArguments().getDouble(RUNTIME))); - runtimeLabel.setText(getArguments().getBoolean(IS_TOTAL_RUNTIME) ? R.string.TestResults_Summary_Hero_Runtime : R.string.TestResults_Details_Hero_Runtime); + binding.runtime.setText(getString(R.string.f, getArguments().getDouble(RUNTIME))); + binding.runtimeLabel.setText(getArguments().getBoolean(IS_TOTAL_RUNTIME) ? R.string.TestResults_Summary_Hero_Runtime : R.string.TestResults_Details_Hero_Runtime); } else - runtimeBox.setVisibility(View.GONE); + binding.runtimeBox.setVisibility(View.GONE); if (getArguments().containsKey(COUNTRY_CODE)) - country.setText(getArguments().getString(COUNTRY_CODE)); + binding.country.setText(getArguments().getString(COUNTRY_CODE)); else - countryBox.setVisibility(View.GONE); + binding.countryBox.setVisibility(View.GONE); if (getArguments().containsKey(NETWORK)) { Network n = (Network) getArguments().getSerializable(NETWORK); - networkName.setText(Network.getName(networkName.getContext(), n)); - networkDetail.setText(networkDetail.getContext().getString(R.string.twoParamWithBrackets, Network.getAsn(networkDetail.getContext(), n), Network.getLocalizedNetworkType(networkDetail.getContext(), n))); + binding.networkName.setText(Network.getName(binding.networkName.getContext(), n)); + binding.networkDetail.setText( + binding.networkDetail.getContext().getString( + R.string.twoParamWithBrackets, + Network.getAsn(binding.networkDetail.getContext(), n), + Network.getLocalizedNetworkType(binding.networkDetail.getContext(), n) + ) + ); } else - networkBox.setVisibility(View.GONE); - return v; + binding.networkBox.setVisibility(View.GONE); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderMiddleboxFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderMiddleboxFragment.java index 3e4137ccc..c70441cb4 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderMiddleboxFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderMiddleboxFragment.java @@ -5,20 +5,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentResultHeadMiddleboxBinding; -import butterknife.BindView; -import butterknife.ButterKnife; - -@Deprecated public class ResultHeaderMiddleboxFragment extends Fragment { +@Deprecated +public class ResultHeaderMiddleboxFragment extends Fragment { private static final String ANOMALY = "anomaly"; - @BindView(R.id.text) TextView text; public static ResultHeaderMiddleboxFragment newInstance(boolean anomaly) { Bundle args = new Bundle(); @@ -28,11 +23,20 @@ public static ResultHeaderMiddleboxFragment newInstance(boolean anomaly) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; - View v = inflater.inflate(R.layout.fragment_result_head_middlebox, container, false); - ButterKnife.bind(this, v); - text.setText(Html.fromHtml(v.getContext().getString(R.string.normalBold, getString(R.string.Test_Middleboxes_Fullname), getString(getArguments().getBoolean(ANOMALY) ? R.string.TestResults_Summary_Middleboxes_Hero_Found : R.string.TestResults_Summary_Middleboxes_Hero_NotFound)))); - return v; + FragmentResultHeadMiddleboxBinding binding = FragmentResultHeadMiddleboxBinding.inflate(inflater, container, false); + binding.text.setText( + Html.fromHtml( + binding.getRoot().getContext().getString( + R.string.normalBold, + getString(R.string.Test_Middleboxes_Fullname), + getString(getArguments().getBoolean(ANOMALY) ? R.string.TestResults_Summary_Middleboxes_Hero_Found : R.string.TestResults_Summary_Middleboxes_Hero_NotFound) + ) + ) + ); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderPerformanceFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderPerformanceFragment.java index d69da9b36..8ae44721f 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderPerformanceFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderPerformanceFragment.java @@ -4,37 +4,20 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentResultHeadPerformanceBinding; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Result; import org.openobservatory.ooniprobe.test.test.Dash; import org.openobservatory.ooniprobe.test.test.Ndt; -import butterknife.BindView; -import butterknife.ButterKnife; - public class ResultHeaderPerformanceFragment extends Fragment { private static final String RESULT = "result"; public static final float ALPHA_DIS = 0.3f; public static final int ALPHA_ENA = 1; - @BindView(R.id.video) TextView video; - @BindView(R.id.upload) TextView upload; - @BindView(R.id.download) TextView download; - @BindView(R.id.ping) TextView ping; - @BindView(R.id.videoLabel) TextView videoLabel; - @BindView(R.id.downloadLabel) TextView downloadLabel; - @BindView(R.id.uploadLabel) TextView uploadLabel; - @BindView(R.id.pingLabel) TextView pingLabel; - @BindView(R.id.videoUnit) TextView videoUnit; - @BindView(R.id.downloadUnit) TextView downloadUnit; - @BindView(R.id.uploadUnit) TextView uploadUnit; - @BindView(R.id.pingUnit) TextView pingUnit; public static ResultHeaderPerformanceFragment newInstance(Result result) { Bundle args = new Bundle(); @@ -44,32 +27,33 @@ public static ResultHeaderPerformanceFragment newInstance(Result result) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; - View v = inflater.inflate(R.layout.fragment_result_head_performance, container, false); - ButterKnife.bind(this, v); + FragmentResultHeadPerformanceBinding binding = FragmentResultHeadPerformanceBinding.inflate(inflater, container, false); Result result = (Result) getArguments().getSerializable(RESULT); assert result != null; Measurement dashM = result.getMeasurement(Dash.NAME); Measurement ndtM = result.getMeasurement(Ndt.NAME); - video.setText(dashM == null ? R.string.TestResults_NotAvailable : dashM.getTestKeys().getVideoQuality(false)); - upload.setText(ndtM == null ? getString(R.string.TestResults_NotAvailable) : ndtM.getTestKeys().getUpload(getActivity())); - uploadUnit.setText(ndtM == null ? R.string.TestResults_NotAvailable : ndtM.getTestKeys().getUploadUnit()); - download.setText(ndtM == null ? getString(R.string.TestResults_NotAvailable) : ndtM.getTestKeys().getDownload(getActivity())); - downloadUnit.setText(ndtM == null ? R.string.TestResults_NotAvailable : ndtM.getTestKeys().getDownloadUnit()); - ping.setText(ndtM == null ? getString(R.string.TestResults_NotAvailable) : ndtM.getTestKeys().getPing(getActivity())); - videoLabel.setAlpha(dashM == null ? ALPHA_DIS : ALPHA_ENA); - downloadLabel.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - uploadLabel.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - pingLabel.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - video.setAlpha(dashM == null ? ALPHA_DIS : ALPHA_ENA); - download.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - upload.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - ping.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - videoUnit.setAlpha(dashM == null ? ALPHA_DIS : ALPHA_ENA); - downloadUnit.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - uploadUnit.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - pingUnit.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); - return v; + binding.video.setText(dashM == null ? R.string.TestResults_NotAvailable : dashM.getTestKeys().getVideoQuality(false)); + binding.upload.setText(ndtM == null ? getString(R.string.TestResults_NotAvailable) : ndtM.getTestKeys().getUpload(getActivity())); + binding.uploadUnit.setText(ndtM == null ? R.string.TestResults_NotAvailable : ndtM.getTestKeys().getUploadUnit()); + binding.download.setText(ndtM == null ? getString(R.string.TestResults_NotAvailable) : ndtM.getTestKeys().getDownload(getActivity())); + binding.downloadUnit.setText(ndtM == null ? R.string.TestResults_NotAvailable : ndtM.getTestKeys().getDownloadUnit()); + binding.ping.setText(ndtM == null ? getString(R.string.TestResults_NotAvailable) : ndtM.getTestKeys().getPing(getActivity())); + binding.videoLabel.setAlpha(dashM == null ? ALPHA_DIS : ALPHA_ENA); + binding.downloadLabel.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + binding.uploadLabel.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + binding.pingLabel.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + binding.video.setAlpha(dashM == null ? ALPHA_DIS : ALPHA_ENA); + binding.download.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + binding.upload.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + binding.ping.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + binding.videoUnit.setAlpha(dashM == null ? ALPHA_DIS : ALPHA_ENA); + binding.downloadUnit.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + binding.uploadUnit.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + binding.pingUnit.setAlpha(ndtM == null ? ALPHA_DIS : ALPHA_ENA); + return binding.getRoot(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderTBAFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderTBAFragment.java index b7a01a0dd..137325d2f 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderTBAFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/resultHeader/ResultHeaderTBAFragment.java @@ -4,26 +4,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.FragmentResultHeadTbaBinding; import org.openobservatory.ooniprobe.model.database.Result; -import butterknife.BindView; -import butterknife.ButterKnife; - public class ResultHeaderTBAFragment extends Fragment { private static final String RESULT = "result"; - @BindView(R.id.tested) TextView tested; - @BindView(R.id.blocked) TextView blocked; - @BindView(R.id.available) TextView available; - @BindView(R.id.testedTag) TextView testedTag; - @BindView(R.id.blockedTag) TextView blockedTag; - @BindView(R.id.availableTag) TextView availableTag; public static ResultHeaderTBAFragment newInstance(Result result) { Bundle args = new Bundle(); @@ -33,21 +22,22 @@ public static ResultHeaderTBAFragment newInstance(Result result) { return fragment; } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { assert getArguments() != null; - View v = inflater.inflate(R.layout.fragment_result_head_tba, container, false); - ButterKnife.bind(this, v); + FragmentResultHeadTbaBinding binding = FragmentResultHeadTbaBinding.inflate(inflater, container, false); Result result = (Result) getArguments().getSerializable(RESULT); assert result != null; long testedCount = result.countTotalMeasurements(); long blockedCount = result.countAnomalousMeasurements(); long availableCount = result.countOkMeasurements(); - tested.setText(getString(R.string.d, testedCount)); - blocked.setText(getString(R.string.d, blockedCount)); - available.setText(getString(R.string.d, availableCount)); - testedTag.setText(getResources().getQuantityText(R.plurals.TestResults_Summary_Websites_Hero_Tested, (int) testedCount)); - blockedTag.setText(getResources().getQuantityText(R.plurals.TestResults_Summary_Websites_Hero_Blocked, (int) blockedCount)); - availableTag.setText(getResources().getQuantityText(R.plurals.TestResults_Summary_Websites_Hero_Reachable, (int) availableCount)); - return v; + binding.tested.setText(getString(R.string.d, testedCount)); + binding.blocked.setText(getString(R.string.d, blockedCount)); + binding.available.setText(getString(R.string.d, availableCount)); + binding.testedTag.setText(getResources().getQuantityText(R.plurals.TestResults_Summary_Websites_Hero_Tested, (int) testedCount)); + binding.blockedTag.setText(getResources().getQuantityText(R.plurals.TestResults_Summary_Websites_Hero_Blocked, (int) blockedCount)); + binding.availableTag.setText(getResources().getQuantityText(R.plurals.TestResults_Summary_Websites_Hero_Reachable, (int) availableCount)); + return binding.getRoot(); } } From b3848817b62062e0904dc5a3c517ce371fbdb80c Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sun, 27 Aug 2023 11:04:13 +0100 Subject: [PATCH 28/33] Update Onboarding fragments to `ViewBinding` --- .../onboarding/Onboarding1Fragment.java | 19 +++--- .../onboarding/Onboarding2Fragment.java | 38 ++++++------ .../onboarding/Onboarding3Fragment.java | 40 ++++++------- .../OnboardingAutoTestFragment.java | 25 ++++---- .../onboarding/OnboardingCrashFragment.java | 21 +++---- .../OnboardingDialogPopquizFragment.java | 59 ++++++++----------- .../OnboardingDialogWarningFragment.java | 28 ++++----- 7 files changed, 97 insertions(+), 133 deletions(-) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding1Fragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding1Fragment.java index ddc203fbb..54382527a 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding1Fragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding1Fragment.java @@ -4,24 +4,21 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - -import org.openobservatory.ooniprobe.R; - -import butterknife.ButterKnife; -import butterknife.OnClick; +import org.openobservatory.ooniprobe.databinding.FragmentOnboarding1Binding; public class Onboarding1Fragment extends Fragment { - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_onboarding_1, container, false); - ButterKnife.bind(this, v); - return v; + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + FragmentOnboarding1Binding binding = FragmentOnboarding1Binding.inflate(inflater, container, false); + binding.master.setOnClickListener(v -> masterClick()); + return binding.getRoot(); } - @OnClick(R.id.master) void masterClick() { + void masterClick() { getParentFragmentManager().beginTransaction().replace(android.R.id.content, new Onboarding2Fragment()).commit(); } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding2Fragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding2Fragment.java index 663da5a4c..fddbc294b 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding2Fragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding2Fragment.java @@ -6,41 +6,36 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; +import org.openobservatory.ooniprobe.databinding.FragmentOnboarding2Binding; public class Onboarding2Fragment extends Fragment implements OnboardingDialogPopquizFragment.OnboardingPopquizInterface, OnboardingDialogWarningFragment.OnboardingWarningInterface { - @BindView(R.id.bullet1) TextView bullet1; - @BindView(R.id.bullet2) TextView bullet2; - @BindView(R.id.bullet3) TextView bullet3; - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_onboarding_2, container, false); - ButterKnife.bind(this, v); - bullet1.setText(getString(R.string.bullet, getString(R.string.Onboarding_ThingsToKnow_Bullet_1))); - bullet2.setText(getString(R.string.bullet, getString(R.string.Onboarding_ThingsToKnow_Bullet_2))); - bullet3.setText(getString(R.string.bullet, getString(R.string.Onboarding_ThingsToKnow_Bullet_3))); - return v; + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + FragmentOnboarding2Binding binding = FragmentOnboarding2Binding.inflate(inflater, container, false); + binding.bullet1.setText(getString(R.string.bullet, getString(R.string.Onboarding_ThingsToKnow_Bullet_1))); + binding.bullet2.setText(getString(R.string.bullet, getString(R.string.Onboarding_ThingsToKnow_Bullet_2))); + binding.bullet3.setText(getString(R.string.bullet, getString(R.string.Onboarding_ThingsToKnow_Bullet_3))); + binding.master.setOnClickListener(v -> masterClick()); + binding.slave.setOnClickListener(v -> slaveClick()); + return binding.getRoot(); } - @OnClick(R.id.master) void masterClick() { + void masterClick() { OnboardingDialogPopquizFragment.newInstance(R.string.Onboarding_PopQuiz_1_Title, R.string.Onboarding_PopQuiz_1_Question).show(getChildFragmentManager(), null); } - @OnClick(R.id.slave) void slaveClick() { + void slaveClick() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://ooni.io/about/risks/"))); } - @Override public void onPopquizResult(int questionResId, boolean positive) { + @Override + public void onPopquizResult(int questionResId, boolean positive) { if (questionResId == R.string.Onboarding_PopQuiz_1_Question) { if (positive) OnboardingDialogPopquizFragment.newInstance(R.string.Onboarding_PopQuiz_2_Title, R.string.Onboarding_PopQuiz_2_Question).show(getChildFragmentManager(), null); @@ -54,7 +49,8 @@ public class Onboarding2Fragment extends Fragment implements OnboardingDialogPop } } - @Override public void onWarningResult(int questionResId) { + @Override + public void onWarningResult(int questionResId) { if (questionResId == R.string.Onboarding_PopQuiz_1_Wrong_Paragraph) OnboardingDialogPopquizFragment.newInstance(R.string.Onboarding_PopQuiz_2_Title, R.string.Onboarding_PopQuiz_2_Question).show(getChildFragmentManager(), null); else if (questionResId == R.string.Onboarding_PopQuiz_2_Wrong_Paragraph) diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding3Fragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding3Fragment.java index cc649e834..005204e37 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding3Fragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/Onboarding3Fragment.java @@ -4,48 +4,42 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.activity.MainActivity; import org.openobservatory.ooniprobe.common.Application; import org.openobservatory.ooniprobe.common.PreferenceManager; import org.openobservatory.ooniprobe.common.ThirdPartyServices; import org.openobservatory.ooniprobe.common.service.ServiceUtil; +import org.openobservatory.ooniprobe.databinding.FragmentOnboarding3Binding; +import ru.noties.markwon.Markwon; import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import ru.noties.markwon.Markwon; - public class Onboarding3Fragment extends Fragment { @Inject PreferenceManager preferenceManager; - @BindView(R.id.bullet1) TextView bullet1; - @BindView(R.id.bullet2) TextView bullet2; - @BindView(R.id.bullet3) TextView bullet3; - @BindView(R.id.paragraph) TextView paragraph; - - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { ((Application) getActivity().getApplication()).getFragmentComponent().inject(this); - View v = inflater.inflate(R.layout.fragment_onboarding_3, container, false); - ButterKnife.bind(this, v); - bullet1.setText(getString(R.string.bullet, getString(R.string.Onboarding_DefaultSettings_Bullet_1))); - bullet2.setText(getString(R.string.bullet, getString(R.string.Onboarding_DefaultSettings_Bullet_2))); - bullet3.setText(getString(R.string.bullet, getString(R.string.Onboarding_DefaultSettings_Bullet_3))); - Markwon.setMarkdown(paragraph, getString(R.string.Onboarding_DefaultSettings_Paragraph)); - return v; + FragmentOnboarding3Binding binding = FragmentOnboarding3Binding.inflate(inflater, container, false); + binding.bullet1.setText(getString(R.string.bullet, getString(R.string.Onboarding_DefaultSettings_Bullet_1))); + binding.bullet2.setText(getString(R.string.bullet, getString(R.string.Onboarding_DefaultSettings_Bullet_2))); + binding.bullet3.setText(getString(R.string.bullet, getString(R.string.Onboarding_DefaultSettings_Bullet_3))); + Markwon.setMarkdown(binding.paragraph, getString(R.string.Onboarding_DefaultSettings_Paragraph)); + + binding.master.setOnClickListener(v -> masterClick()); + binding.slave.setOnClickListener(v -> slaveClick()); + + return binding.getRoot(); } - @OnClick(R.id.master) void masterClick() { + void masterClick() { preferenceManager.setShowOnboarding(false); ThirdPartyServices.reloadConsents((Application) getActivity().getApplication()); startAutoTestIfNeeded(); @@ -53,7 +47,7 @@ public class Onboarding3Fragment extends Fragment { getActivity().finish(); } - @OnClick(R.id.slave) void slaveClick() { + void slaveClick() { preferenceManager.setShowOnboarding(false); startAutoTestIfNeeded(); startActivity(MainActivity.newIntent(getActivity(), R.id.settings)); diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingAutoTestFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingAutoTestFragment.java index 38f520820..01ebce218 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingAutoTestFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingAutoTestFragment.java @@ -10,42 +10,39 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - +import localhost.toolkit.app.fragment.ConfirmDialogFragment; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.Application; import org.openobservatory.ooniprobe.common.PreferenceManager; import org.openobservatory.ooniprobe.common.ThirdPartyServices; - -import java.io.Serializable; +import org.openobservatory.ooniprobe.databinding.FragmentOnboardingAutotestBinding; import javax.inject.Inject; - -import butterknife.ButterKnife; -import butterknife.OnClick; -import localhost.toolkit.app.fragment.ConfirmDialogFragment; +import java.io.Serializable; public class OnboardingAutoTestFragment extends Fragment implements ConfirmDialogFragment.OnConfirmedListener { @Inject PreferenceManager preferenceManager; public static final String BATTERY_DIALOG = "battery_optimization"; @Nullable - @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { ((Application) getActivity().getApplication()).getFragmentComponent().inject(this); - View v = inflater.inflate(R.layout.fragment_onboarding_autotest, container, false); - ButterKnife.bind(this, v); - return v; + FragmentOnboardingAutotestBinding binding = FragmentOnboardingAutotestBinding.inflate(inflater, container, false); + binding.master.setOnClickListener(v -> masterClick()); + binding.slave.setOnClickListener(v -> slaveClick()); + return binding.getRoot(); } - @OnClick(R.id.master) void masterClick() { + void masterClick() { enableAutoTest(); } - @OnClick(R.id.slave) void slaveClick() { + void slaveClick() { next(); } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingCrashFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingCrashFragment.java index d3ece3295..1c4c97b94 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingCrashFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingCrashFragment.java @@ -4,32 +4,29 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; - -import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.common.Application; import org.openobservatory.ooniprobe.common.ThirdPartyServices; - -import butterknife.ButterKnife; -import butterknife.OnClick; +import org.openobservatory.ooniprobe.databinding.FragmentOnboardingCrashBinding; public class OnboardingCrashFragment extends Fragment { @Nullable - @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_onboarding_crash, container, false); - ButterKnife.bind(this, v); - return v; + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + FragmentOnboardingCrashBinding binding = FragmentOnboardingCrashBinding.inflate(inflater, container, false); + binding.master.setOnClickListener(v -> masterClick()); + binding.slave.setOnClickListener(v -> slaveClick()); + return binding.getRoot(); } - @OnClick(R.id.master) void masterClick() { + void masterClick() { ThirdPartyServices.acceptCrash((Application) getActivity().getApplication()); getParentFragmentManager().beginTransaction().replace(android.R.id.content, new Onboarding3Fragment()).commit(); } - @OnClick(R.id.slave) void slaveClick() { + void slaveClick() { getParentFragmentManager().beginTransaction().replace(android.R.id.content, new Onboarding3Fragment()).commit(); } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingDialogPopquizFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingDialogPopquizFragment.java index d1f93267a..8321f0f89 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingDialogPopquizFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingDialogPopquizFragment.java @@ -9,28 +9,16 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.widget.LinearLayout; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; - -import com.airbnb.lottie.LottieAnimationView; - import org.openobservatory.ooniprobe.R; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; +import org.openobservatory.ooniprobe.databinding.FragmentOnboardingDialogPopquizBinding; public class OnboardingDialogPopquizFragment extends DialogFragment { private static final String TITLE_RES_ID = "titleResId"; private static final String QUESTION_RES_ID = "questionResId"; - @BindView(R.id.title) @Nullable TextView title; - @BindView(R.id.question) TextView question; - @BindView(R.id.dialog) LinearLayout dialog; - @BindView(R.id.animation) LottieAnimationView animation; + private FragmentOnboardingDialogPopquizBinding binding; public static OnboardingDialogPopquizFragment newInstance(int titleResId, int questionResId) { Bundle args = new Bundle(); @@ -53,42 +41,45 @@ public void onStart() { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { assert getArguments() != null; - View v = inflater.inflate(R.layout.fragment_onboarding_dialog_popquiz, container, false); - ButterKnife.bind(this, v); - if (title != null) - title.setText(getArguments().getInt(TITLE_RES_ID)); - question.setText(getArguments().getInt(QUESTION_RES_ID)); - return v; + binding = FragmentOnboardingDialogPopquizBinding.inflate(inflater, container, false); + if (binding.title != null) + binding.title.setText(getArguments().getInt(TITLE_RES_ID)); + binding.question.setText(getArguments().getInt(QUESTION_RES_ID)); + + binding.positive.setOnClickListener(v -> positiveClick()); + binding.negative.setOnClickListener(v -> negativeClick()); + + return binding.getRoot(); } - @OnClick(R.id.positive) void positiveClick() { - animation.setBackgroundResource(R.drawable.dialog_green); - animation.setAnimation("anim/checkMark.json"); - animation.setVisibility(View.VISIBLE); - dialog.setVisibility(View.INVISIBLE); - animation.addAnimatorListener(new AnimatorListenerAdapter() { + void positiveClick() { + binding.animation.setBackgroundResource(R.drawable.dialog_green); + binding.animation.setAnimation("anim/checkMark.json"); + binding.animation.setVisibility(View.VISIBLE); + binding.dialog.setVisibility(View.INVISIBLE); + binding.animation.addAnimatorListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { dismiss(); ((OnboardingPopquizInterface) getParentFragment()).onPopquizResult(getArguments().getInt(QUESTION_RES_ID), true); } }); - animation.playAnimation(); + binding.animation.playAnimation(); } - @OnClick(R.id.negative) void negativeClick() { - animation.setBackgroundResource(R.drawable.dialog_red); - animation.setAnimation("anim/crossMark.json"); - animation.setVisibility(View.VISIBLE); - dialog.setVisibility(View.INVISIBLE); - animation.addAnimatorListener(new AnimatorListenerAdapter() { + void negativeClick() { + binding.animation.setBackgroundResource(R.drawable.dialog_red); + binding.animation.setAnimation("anim/crossMark.json"); + binding.animation.setVisibility(View.VISIBLE); + binding.dialog.setVisibility(View.INVISIBLE); + binding.animation.addAnimatorListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { dismiss(); ((OnboardingPopquizInterface) getParentFragment()).onPopquizResult(getArguments().getInt(QUESTION_RES_ID), false); } }); - animation.playAnimation(); + binding.animation.playAnimation(); } public interface OnboardingPopquizInterface { diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingDialogWarningFragment.java b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingDialogWarningFragment.java index 5cc405474..f8e6102eb 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingDialogWarningFragment.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/onboarding/OnboardingDialogWarningFragment.java @@ -7,24 +7,13 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.widget.LinearLayout; -import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; - -import org.openobservatory.ooniprobe.R; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; +import org.openobservatory.ooniprobe.databinding.FragmentOnboardingDialogWarningBinding; public class OnboardingDialogWarningFragment extends DialogFragment { private static final String QUESTION_RES_ID = "questionResId"; - @BindView(R.id.title) @Nullable TextView title; - @BindView(R.id.question) TextView question; - @BindView(R.id.dialog) LinearLayout dialog; public static OnboardingDialogWarningFragment newInstance(int questionResId) { Bundle args = new Bundle(); @@ -46,17 +35,20 @@ public void onStart() { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { assert getArguments() != null; - View v = inflater.inflate(R.layout.fragment_onboarding_dialog_warning, container, false); - ButterKnife.bind(this, v); - question.setText(getArguments().getInt(QUESTION_RES_ID)); - return v; + FragmentOnboardingDialogWarningBinding binding = FragmentOnboardingDialogWarningBinding.inflate(inflater, container, false); + binding.question.setText(getArguments().getInt(QUESTION_RES_ID)); + + binding.positive.setOnClickListener(v -> positiveClick()); + binding.negative.setOnClickListener(v -> negativeClick()); + + return binding.getRoot(); } - @OnClick(R.id.positive) void positiveClick() { + void positiveClick() { dismiss(); } - @OnClick(R.id.negative) void negativeClick() { + void negativeClick() { dismiss(); ((OnboardingWarningInterface) getParentFragment()).onWarningResult(getArguments().getInt(QUESTION_RES_ID)); } From 6428bca4747562b2b9594197e1ab55d90093985b Mon Sep 17 00:00:00 2001 From: Norbel AMBANUMBEN Date: Sat, 9 Sep 2023 14:32:52 +0100 Subject: [PATCH 29/33] Revert "Chore: Update Gradle and Android core dependencies" --- .github/workflows/build.yml | 6 +-- .github/workflows/emulator.yml | 6 +-- .github/workflows/test.yml | 6 +-- app/build.gradle | 42 ++++++++++--------- app/jacoco.gradle | 22 ++++------ .../ooniprobe/common/ThirdPartyServices.java | 5 +-- build.gradle | 8 ++-- engine/build.gradle | 9 ++-- gradle.properties | 17 +------- gradle/wrapper/gradle-wrapper.properties | 2 +- 10 files changed, 52 insertions(+), 71 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 240c10008..6ed6c7a7e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,10 +10,10 @@ jobs: - "StableFullRelease" - "StableFdroidRelease" steps: - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v2 with: - java-version: '17' + java-version: '11' distribution: 'temurin' - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v2 - run: ./gradlew build${{ matrix.version }} && ./gradlew clean diff --git a/.github/workflows/emulator.yml b/.github/workflows/emulator.yml index 5cd77a8df..0a599c15a 100644 --- a/.github/workflows/emulator.yml +++ b/.github/workflows/emulator.yml @@ -15,12 +15,12 @@ jobs: api-level: [29] target: [google_apis] steps: - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v2 with: - java-version: '17' + java-version: '11' distribution: 'temurin' - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: run tests uses: reactivecircus/android-emulator-runner@v2 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 35a1bfb9c..e678fedd6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,12 +5,12 @@ jobs: test: runs-on: macos-latest steps: - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v2 with: - java-version: '17' + java-version: '11' distribution: 'temurin' - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v2 - run: ./gradlew testStableFullRelease - name: uploads test results uses: actions/upload-artifact@v2 diff --git a/app/build.gradle b/app/build.gradle index 801f7246c..ac15c07d7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -53,7 +53,7 @@ android { } } - flavorDimensions = ['testing', 'license'] + flavorDimensions 'testing', 'license' productFlavors { stable { dimension 'testing' @@ -90,6 +90,10 @@ android { setIgnore(true) } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildFeatures { viewBinding = true } @@ -102,9 +106,9 @@ dependencies { // AndroidX implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.lifecycle:lifecycle-process:2.6.1' + implementation 'androidx.lifecycle:lifecycle-process:2.5.1' implementation 'androidx.preference:preference:1.2.0' - implementation 'com.google.android.material:material:1.9.0' + implementation 'com.google.android.material:material:1.6.1' implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' implementation 'com.google.guava:guava:30.1.1-android' implementation 'androidx.legacy:legacy-support-v4:1.0.0' @@ -123,7 +127,7 @@ dependencies { annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' implementation 'com.github.xanscale.LocalhostToolkit:app:19.05.01' - implementation 'com.airbnb.android:lottie:6.0.0' + implementation 'com.airbnb.android:lottie:3.0.7' implementation 'com.google.code.gson:gson:2.8.9' implementation 'ru.noties:markwon:2.0.1' implementation 'commons-io:commons-io:2.6' @@ -133,13 +137,13 @@ dependencies { // Flavor fullImplementation platform('com.google.firebase:firebase-bom:26.3.0') fullImplementation 'com.google.firebase:firebase-messaging' - fullImplementation 'ly.count.android:sdk:23.6.0' + fullImplementation 'ly.count.android:sdk:21.11.0' fullImplementation 'io.sentry:sentry-android:6.3.0' fullImplementation 'com.google.android.play:core:1.10.3' // Dependency Injection - implementation 'com.google.dagger:dagger:2.44.2' - annotationProcessor 'com.google.dagger:dagger-compiler:2.44.2' + implementation 'com.google.dagger:dagger:2.36' + annotationProcessor 'com.google.dagger:dagger-compiler:2.36' // Logger implementation project(':applogger') @@ -147,35 +151,35 @@ dependencies { // Testing // Unit Testing testImplementation 'junit:junit:4.13.2' - testImplementation 'androidx.test:core:1.5.0' - testImplementation 'androidx.test:runner:1.5.2' - testImplementation 'androidx.test:rules:1.5.0' + testImplementation 'androidx.test:core:1.4.0' + testImplementation 'androidx.test:runner:1.4.0' + testImplementation 'androidx.test:rules:1.4.0' testImplementation 'org.mockito:mockito-core:4.6.1' testImplementation 'org.mockito:mockito-inline:4.6.1' - testImplementation 'org.robolectric:robolectric:4.10.3' + testImplementation 'org.robolectric:robolectric:4.5.1' testImplementation 'com.github.blocoio:faker:1.2.8' testImplementation 'org.ooni:oonimkall:2023.07.18-162729' - testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.44.2' + testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.36' // Instrumentation Testing androidTestImplementation 'tools.fastlane:screengrab:2.0.0' androidTestImplementation 'com.github.blocoio:faker:1.2.8' - androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test:rules:1.5.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1' - androidTestImplementation('androidx.test.espresso:espresso-contrib:3.5.1') { + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test:rules:1.4.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0' + androidTestImplementation('androidx.test.espresso:espresso-contrib:3.4.0') { exclude group: 'com.android.support', module: 'appcompat' exclude group: 'com.android.support', module: 'support-v4' exclude module: 'recyclerview-v7' } - androidTestImplementation('androidx.test.espresso:espresso-core:3.5.1') { + androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0') { exclude group: 'com.android.support', module: 'appcompat' exclude group: 'com.android.support', module: 'support-v4' exclude module: 'recyclerview-v7' } androidTestImplementation('com.schibsted.spain:barista:3.9.0') - androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.44.2" + androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.36" } static def versionCodeDate() { diff --git a/app/jacoco.gradle b/app/jacoco.gradle index add082a31..816940653 100644 --- a/app/jacoco.gradle +++ b/app/jacoco.gradle @@ -1,7 +1,7 @@ apply plugin: 'jacoco' jacoco { - toolVersion '0.8.7' + toolVersion '0.8.5' } task jacocoAndroidTestReport(type: JacocoReport) { @@ -48,19 +48,13 @@ task jacocoAndroidTestReport(type: JacocoReport) { executionData.from += fileTree(dir: codeCoverageDataLocation, includes: ['**/*.ec']) } - reports { - html { - enabled true - destination file("${buildDir}/reports/coverage") - } - xml { - enabled true - destination file("${buildDir}/reports/coverage.xml") - } - csv { - enabled false - } - } + reports { + html.enabled true + html.destination file("${buildDir}/reports/coverage") + xml.enabled true + xml.destination file("${buildDir}/reports/coverage.xml") + csv.enabled false + } doLast { println "Wrote HTML coverage report to ${reports.html.destination}/index.html" diff --git a/app/src/full/java/org/openobservatory/ooniprobe/common/ThirdPartyServices.java b/app/src/full/java/org/openobservatory/ooniprobe/common/ThirdPartyServices.java index bfd47d05e..80b6c731d 100644 --- a/app/src/full/java/org/openobservatory/ooniprobe/common/ThirdPartyServices.java +++ b/app/src/full/java/org/openobservatory/ooniprobe/common/ThirdPartyServices.java @@ -20,7 +20,6 @@ import io.sentry.android.core.SentryAndroid; import ly.count.android.sdk.Countly; import ly.count.android.sdk.CountlyConfig; -import ly.count.android.sdk.messaging.CountlyConfigPush; import ly.count.android.sdk.messaging.CountlyPush; public class ThirdPartyServices { @@ -49,9 +48,7 @@ public static void initCountly(Application app) { public static void registerPush(Application app){ if (Countly.sharedInstance().isInitialized()) { - CountlyConfigPush countlyConfigPush = new CountlyConfigPush(app, BuildConfig.DEBUG ? Countly.CountlyMessagingMode.TEST : Countly.CountlyMessagingMode.PRODUCTION) - .setProvider(Countly.CountlyMessagingProvider.FCM); - CountlyPush.init(countlyConfigPush); + CountlyPush.init(app, BuildConfig.DEBUG ? Countly.CountlyMessagingMode.TEST : Countly.CountlyMessagingMode.PRODUCTION); NotificationUtility.setChannel(app, CountlyPush.CHANNEL_ID, app.getString(R.string.Settings_Notifications_Label), true, true, true); ThirdPartyServices.setToken(app); } diff --git a/build.gradle b/build.gradle index fadbb2582..1fcb28081 100644 --- a/build.gradle +++ b/build.gradle @@ -6,9 +6,9 @@ buildscript { maven { url "https://jitpack.io" } } dependencies { - classpath 'com.android.tools.build:gradle:8.0.2' - classpath 'com.google.gms:google-services:4.3.15' - classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0' + classpath 'com.android.tools.build:gradle:7.4.1' + classpath 'com.google.gms:google-services:4.3.13' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21' } } @@ -21,6 +21,6 @@ allprojects { } } -tasks.register('clean', Delete) { +task clean(type: Delete) { delete rootProject.buildDir } diff --git a/engine/build.gradle b/engine/build.gradle index d9da10f94..93facfd52 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -1,11 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdk 33 + compileSdkVersion 30 + buildToolsVersion "30.0.3" defaultConfig { - minSdk 19 - targetSdk 33 + minSdkVersion 19 + targetSdkVersion 30 } compileOptions { @@ -13,7 +14,7 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } - flavorDimensions = ['testing'] + flavorDimensions 'testing' productFlavors { stable { dimension 'testing' diff --git a/gradle.properties b/gradle.properties index eb2a51767..8de505811 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,24 +6,9 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -android.defaults.buildfeatures.buildconfig=true android.enableJetifier=true -android.nonFinalResIds=false -android.nonTransitiveRClass=false android.useAndroidX=true -# https://github.com/JakeWharton/butterknife/issues/1686 -org.gradle.jvmargs=-Xmx1920M \ ---add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ ---add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED - +org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3a0290794..2ec77e51a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From c8c98d421e87b40ae47ed8b1fc3228e6ec6ff7ee Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Sun, 10 Sep 2023 07:59:04 +0100 Subject: [PATCH 30/33] Fix duplicate content root and update dependencies to enable more fluent runs from the IDE --- app/build.gradle | 47 +++++-------- settings.gradle | 1 + shared-test/.gitignore | 1 + shared-test/build.gradle | 66 +++++++++++++++++++ shared-test/src/main/AndroidManifest.xml | 4 ++ .../ooniprobe/di/TestAppComponent.java | 0 .../ooniprobe/di/TestAppModule.java | 0 .../ooniprobe/di/TestApplication.java | 0 .../ooniprobe/factory/EventResultFactory.java | 0 .../ooniprobe/factory/JsonResultFactory.java | 0 .../ooniprobe/factory/MeasurementFactory.java | 0 .../ooniprobe/factory/NetworkFactory.java | 0 .../ooniprobe/factory/ResponseFactory.java | 0 .../ooniprobe/factory/ResultFactory.java | 0 .../ooniprobe/factory/TestKeyFactory.java | 0 .../ooniprobe/factory/UrlFactory.java | 0 .../ooniprobe/utils/DatabaseUtils.java | 0 .../ooniprobe/utils/FormattingUtils.java | 0 .../ooniprobe/utils/TestSuiteUtils.java | 0 .../utils/models/TestSuiteMeasurements.java | 0 20 files changed, 87 insertions(+), 32 deletions(-) create mode 100644 shared-test/.gitignore create mode 100644 shared-test/build.gradle create mode 100644 shared-test/src/main/AndroidManifest.xml rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/di/TestAppComponent.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/di/TestAppModule.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/di/TestApplication.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/factory/EventResultFactory.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/factory/JsonResultFactory.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/factory/MeasurementFactory.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/factory/NetworkFactory.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/factory/ResponseFactory.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/factory/ResultFactory.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/factory/TestKeyFactory.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/factory/UrlFactory.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/utils/DatabaseUtils.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/utils/FormattingUtils.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/utils/TestSuiteUtils.java (100%) rename {app/src/sharedTest => shared-test/src/main}/java/org/openobservatory/ooniprobe/utils/models/TestSuiteMeasurements.java (100%) diff --git a/app/build.gradle b/app/build.gradle index ac15c07d7..6f8d001bb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,18 +41,6 @@ android { } } - // Shared test code between Unit and Instrumented tests - sourceSets { - androidTest { - java.srcDirs += "src/sharedTest/java" - resources.srcDirs += "src/sharedTest/resources" - } - test { - java.srcDirs += "src/sharedTest/java" - resources.srcDirs += "src/sharedTest/resources" - } - } - flavorDimensions 'testing', 'license' productFlavors { stable { @@ -150,36 +138,31 @@ dependencies { // Testing // Unit Testing + testImplementation project(':shared-test') testImplementation 'junit:junit:4.13.2' - testImplementation 'androidx.test:core:1.4.0' - testImplementation 'androidx.test:runner:1.4.0' - testImplementation 'androidx.test:rules:1.4.0' - testImplementation 'org.mockito:mockito-core:4.6.1' + testImplementation 'androidx.test:core:1.5.0' + testImplementation 'androidx.test:runner:1.5.2' + testImplementation 'androidx.test:rules:1.5.0' + testImplementation 'org.mockito:mockito-core:5.3.1' testImplementation 'org.mockito:mockito-inline:4.6.1' - testImplementation 'org.robolectric:robolectric:4.5.1' + testImplementation 'org.robolectric:robolectric:4.10.3' testImplementation 'com.github.blocoio:faker:1.2.8' testImplementation 'org.ooni:oonimkall:2023.07.18-162729' testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.36' // Instrumentation Testing + androidTestImplementation project(':shared-test') androidTestImplementation 'tools.fastlane:screengrab:2.0.0' androidTestImplementation 'com.github.blocoio:faker:1.2.8' - androidTestImplementation 'androidx.test:runner:1.4.0' - androidTestImplementation 'androidx.test:rules:1.4.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0' - androidTestImplementation('androidx.test.espresso:espresso-contrib:3.4.0') { - exclude group: 'com.android.support', module: 'appcompat' - exclude group: 'com.android.support', module: 'support-v4' - exclude module: 'recyclerview-v7' - } - androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0') { - exclude group: 'com.android.support', module: 'appcompat' - exclude group: 'com.android.support', module: 'support-v4' - exclude module: 'recyclerview-v7' - } - androidTestImplementation('com.schibsted.spain:barista:3.9.0') + androidTestImplementation 'androidx.test:runner:1.5.2' + androidTestImplementation 'androidx.test:rules:1.5.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1' + androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation 'com.schibsted.spain:barista:3.9.0' androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.36" + } static def versionCodeDate() { diff --git a/settings.gradle b/settings.gradle index 8a8583d06..ee1a417a5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,3 +2,4 @@ include ':app' include ':engine' include ':engine-experimental' include ':applogger' +include ':shared-test' diff --git a/shared-test/.gitignore b/shared-test/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/shared-test/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/shared-test/build.gradle b/shared-test/build.gradle new file mode 100644 index 000000000..5ef394ce7 --- /dev/null +++ b/shared-test/build.gradle @@ -0,0 +1,66 @@ +plugins { + id 'com.android.library' +} + +android { + namespace 'org.openobservatory.ooniprobe.shared.test' + compileSdk 33 + + defaultConfig { + minSdk 21 + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + flavorDimensions = ['testing', 'license'] + productFlavors { + stable { + dimension 'testing' + } + experimental { + dimension 'testing' + } + dev { + dimension 'testing' + } + + fdroid { + dimension 'license' + } + full { + dimension 'license' + } + } +} + +dependencies { + implementation project(":engine") + implementation project(":app") + + // Dependency Injection (https://dagger.dev/) + implementation 'com.google.dagger:dagger:2.36' + annotationProcessor 'com.google.dagger:dagger-compiler:2.36' + + // Database Library (https://github.com/agrosner/DBFlow) + implementation 'com.github.Raizlabs.DBFlow:dbflow-core:4.2.4' + implementation 'com.github.Raizlabs.DBFlow:dbflow:4.2.4' + annotationProcessor 'com.github.Raizlabs.DBFlow:dbflow-processor:4.2.4' + + // Gson Serialization Library (https://github.com/google/gson) + implementation 'com.google.code.gson:gson:2.8.9' + + implementation 'com.github.blocoio:faker:1.2.8' + implementation 'commons-io:commons-io:2.6' + + // Networking Library (https://square.github.io/retrofit/) + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' + + implementation 'androidx.appcompat:appcompat:1.6.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} \ No newline at end of file diff --git a/shared-test/src/main/AndroidManifest.xml b/shared-test/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a5918e68a --- /dev/null +++ b/shared-test/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/di/TestAppComponent.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/di/TestAppComponent.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/di/TestAppComponent.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/di/TestAppComponent.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/di/TestAppModule.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/di/TestAppModule.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/di/TestAppModule.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/di/TestAppModule.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/di/TestApplication.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/di/TestApplication.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/di/TestApplication.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/di/TestApplication.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/EventResultFactory.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/factory/EventResultFactory.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/EventResultFactory.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/factory/EventResultFactory.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/JsonResultFactory.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/factory/JsonResultFactory.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/JsonResultFactory.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/factory/JsonResultFactory.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/MeasurementFactory.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/factory/MeasurementFactory.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/MeasurementFactory.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/factory/MeasurementFactory.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/NetworkFactory.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/factory/NetworkFactory.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/NetworkFactory.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/factory/NetworkFactory.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/ResponseFactory.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/factory/ResponseFactory.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/ResponseFactory.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/factory/ResponseFactory.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/ResultFactory.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/factory/ResultFactory.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/ResultFactory.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/factory/ResultFactory.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/TestKeyFactory.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/factory/TestKeyFactory.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/TestKeyFactory.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/factory/TestKeyFactory.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/UrlFactory.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/factory/UrlFactory.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/factory/UrlFactory.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/factory/UrlFactory.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/utils/DatabaseUtils.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/utils/DatabaseUtils.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/utils/DatabaseUtils.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/utils/DatabaseUtils.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/utils/FormattingUtils.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/utils/FormattingUtils.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/utils/FormattingUtils.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/utils/FormattingUtils.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/utils/TestSuiteUtils.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/utils/TestSuiteUtils.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/utils/TestSuiteUtils.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/utils/TestSuiteUtils.java diff --git a/app/src/sharedTest/java/org/openobservatory/ooniprobe/utils/models/TestSuiteMeasurements.java b/shared-test/src/main/java/org/openobservatory/ooniprobe/utils/models/TestSuiteMeasurements.java similarity index 100% rename from app/src/sharedTest/java/org/openobservatory/ooniprobe/utils/models/TestSuiteMeasurements.java rename to shared-test/src/main/java/org/openobservatory/ooniprobe/utils/models/TestSuiteMeasurements.java From c82bad7f75b7f6ee512fbdd6a15e8cc555449c52 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Wed, 13 Sep 2023 15:17:13 +0100 Subject: [PATCH 31/33] Remove remaining references to `butterknife` --- NOTICE | 1 - app/build.gradle | 3 -- .../ooniprobe/activity/MainActivity.java | 4 --- .../ooniprobe/item/DateItem.java | 18 +++++------ .../ooniprobe/item/FailedItem.java | 30 ++++++++----------- .../ooniprobe/item/SeperatorItem.java | 11 +++---- .../ooniprobe/item/TextItem.java | 18 +++++------ 7 files changed, 30 insertions(+), 55 deletions(-) diff --git a/NOTICE b/NOTICE index 4b365e82d..5fc016898 100644 --- a/NOTICE +++ b/NOTICE @@ -19,7 +19,6 @@ Terms: https://firebase.google.com/terms/ - easypermissions - LocalhostToolkit -- butterknife - DBFlow - LocalhostToolkit - MarkdownView diff --git a/app/build.gradle b/app/build.gradle index b1b52ef1b..9f2e1f496 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -126,9 +126,6 @@ dependencies { implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' - implementation 'com.jakewharton:butterknife:10.2.3' - annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' - implementation 'com.github.xanscale.LocalhostToolkit:app:19.05.01' implementation 'com.airbnb.android:lottie:3.0.7' implementation 'com.google.code.gson:gson:2.8.9' diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/MainActivity.java b/app/src/main/java/org/openobservatory/ooniprobe/activity/MainActivity.java index 66650d8dc..933bfbf88 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/activity/MainActivity.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/MainActivity.java @@ -19,7 +19,6 @@ import androidx.appcompat.app.AppCompatDelegate; import androidx.core.content.ContextCompat; -import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.snackbar.Snackbar; import org.openobservatory.ooniprobe.R; @@ -38,8 +37,6 @@ import javax.inject.Inject; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.app.fragment.ConfirmDialogFragment; public class MainActivity extends AbstractActivity implements ConfirmDialogFragment.OnConfirmedListener { @@ -71,7 +68,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { finish(); } else { - ButterKnife.bind(this); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); binding.bottomNavigation.setOnItemSelectedListener(item -> { diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/DateItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/DateItem.java index 139bfe342..60a6003c5 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/DateItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/DateItem.java @@ -2,20 +2,16 @@ import android.text.format.DateFormat; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; -import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemDateBinding; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; public class DateItem extends HeterogeneousRecyclerItem { @@ -27,19 +23,19 @@ public DateItem(Date extra) { } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_date, viewGroup, false)); + return new ViewHolder(ItemDateBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { - viewHolder.textView.setText(SDF.format(extra)); + viewHolder.binding.textView.setText(SDF.format(extra)); } class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.textView) TextView textView; + ItemDateBinding binding; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolder(ItemDateBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/FailedItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/FailedItem.java index f86a9559a..43171a5f4 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/FailedItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/FailedItem.java @@ -4,19 +4,16 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemFailedBinding; import org.openobservatory.ooniprobe.model.database.Result; import java.util.Locale; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; public class FailedItem extends HeterogeneousRecyclerItem { @@ -30,7 +27,7 @@ public FailedItem(Result extra, View.OnClickListener onClickListener, View.OnLon } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_failed, viewGroup, false)); + return new ViewHolder(ItemFailedBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { @@ -38,25 +35,22 @@ public FailedItem(Result extra, View.OnClickListener onClickListener, View.OnLon viewHolder.itemView.setOnClickListener(onClickListener); viewHolder.itemView.setOnLongClickListener(onLongClickListener); viewHolder.itemView.setBackgroundColor(ContextCompat.getColor(viewHolder.itemView.getContext(), R.color.color_gray2)); - viewHolder.testName.setTextColor(ContextCompat.getColor(viewHolder.itemView.getContext(), R.color.color_gray6)); - viewHolder.icon.setImageResource(extra.getTestSuite().getIcon()); - viewHolder.testName.setText(extra.getTestSuite().getTitle()); + viewHolder.binding.testName.setTextColor(ContextCompat.getColor(viewHolder.itemView.getContext(), R.color.color_gray6)); + viewHolder.binding.icon.setImageResource(extra.getTestSuite().getIcon()); + viewHolder.binding.testName.setText(extra.getTestSuite().getTitle()); String failure_msg = viewHolder.itemView.getContext().getString(R.string.TestResults_Overview_Error); if (extra.failure_msg != null) failure_msg += " - " + extra.failure_msg; - viewHolder.subtitle.setText(failure_msg); - viewHolder.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); + viewHolder.binding.subtitle.setText(failure_msg); + viewHolder.binding.startTime.setText(DateFormat.format(DateFormat.getBestDateTimePattern(Locale.getDefault(), "yMdHm"), extra.start_time)); } class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.testName) TextView testName; - @BindView(R.id.subtitle) TextView subtitle; - @BindView(R.id.startTime) TextView startTime; - @BindView(R.id.icon) ImageView icon; - - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ItemFailedBinding binding; + + ViewHolder(ItemFailedBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } \ No newline at end of file diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/SeperatorItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/SeperatorItem.java index 5b50974d5..70c971b22 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/SeperatorItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/SeperatorItem.java @@ -1,14 +1,12 @@ package org.openobservatory.ooniprobe.item; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; import androidx.recyclerview.widget.RecyclerView; -import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemSeperatorBinding; -import butterknife.ButterKnife; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; public class SeperatorItem extends HeterogeneousRecyclerItem { @@ -18,15 +16,14 @@ public SeperatorItem() { } @Override public ViewHolderImpl onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolderImpl(layoutInflater.inflate(R.layout.item_seperator, viewGroup, false)); + return new ViewHolderImpl(ItemSeperatorBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolderImpl holder) {} static class ViewHolderImpl extends RecyclerView.ViewHolder { - ViewHolderImpl(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolderImpl(ItemSeperatorBinding binding) { + super(binding.getRoot()); } } } diff --git a/app/src/main/java/org/openobservatory/ooniprobe/item/TextItem.java b/app/src/main/java/org/openobservatory/ooniprobe/item/TextItem.java index 9d0bdb097..f3e6349c4 100644 --- a/app/src/main/java/org/openobservatory/ooniprobe/item/TextItem.java +++ b/app/src/main/java/org/openobservatory/ooniprobe/item/TextItem.java @@ -1,16 +1,12 @@ package org.openobservatory.ooniprobe.item; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; -import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.databinding.ItemTextBinding; -import butterknife.BindView; -import butterknife.ButterKnife; import localhost.toolkit.widget.recyclerview.HeterogeneousRecyclerItem; public class TextItem extends HeterogeneousRecyclerItem { @@ -19,19 +15,19 @@ public TextItem(String extra) { } @Override public ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup viewGroup) { - return new ViewHolder(layoutInflater.inflate(R.layout.item_text, viewGroup, false)); + return new ViewHolder(ItemTextBinding.inflate(layoutInflater, viewGroup, false)); } @Override public void onBindViewHolder(ViewHolder viewHolder) { - viewHolder.textView.setText(extra); + viewHolder.binding.textView.setText(extra); } class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.textView) TextView textView; + ItemTextBinding binding; - ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); + ViewHolder(ItemTextBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } From 473d21cb5244590806ba091601fe1e31f7625a78 Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Wed, 11 Oct 2023 13:53:00 +0100 Subject: [PATCH 32/33] Updated the result list layout to prevent text overlap. --- app/src/main/res/layout/fragment_result_list.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/fragment_result_list.xml b/app/src/main/res/layout/fragment_result_list.xml index 8ca0d9956..6d016e49c 100644 --- a/app/src/main/res/layout/fragment_result_list.xml +++ b/app/src/main/res/layout/fragment_result_list.xml @@ -141,7 +141,7 @@ android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"> - @@ -160,7 +160,7 @@ android:entries="@array/filterTests" android:paddingVertical="8dp" android:textAlignment="center" /> - + - \ No newline at end of file + From 5975bf0c4c74f5850a66cba87e6b3c6fdf5b252e Mon Sep 17 00:00:00 2001 From: Norbel Ambanumben Date: Thu, 12 Oct 2023 08:47:48 +0100 Subject: [PATCH 33/33] pull updates for language from transifex --- app/src/main/res/values-my/strings.xml | 38 ++-- app/src/main/res/values-vi/strings.xml | 274 ++++++++++++------------- 2 files changed, 156 insertions(+), 156 deletions(-) diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index 10248fce7..3fa7ffd7c 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -2,7 +2,7 @@ OONI Probe OONI Probe ဆိုတာ ဘာလဲ။ - သင့်အက်ပ်သည် အင်တာနက် ဆင်ဆာဖြတ်တောက်မှုကို တိုင်းတာရန် သင့်အက်ပ်။\n\nဝဘ်ဆိုက်များနှင့် ဆိုရှယ်မီဒီယာအက်ပ်များကို ပိတ်ဆို့ နေပါသလား။ သင့်အင်တာနက် ချိတ်ဆက်မှုသည် ပုံမှန်မဟုတ်ဘဲ နှေးနေပါသလား။\n\n၄င်းအကြောင်းအရာတို့ကို သိရှိရန် OONI Probe ကိုဖွင့်ပါ။ + သင့်အက်ပ်သည် အင်တာနက် ဆင်ဆာဖြတ်တောက်မှုကို တိုင်းတာရန်။\n\nဝဘ်ဆိုက်များနှင့် ဆိုရှယ်မီဒီယာအက်ပ်များကို ပိတ်ဆို့ နေပါသလား။ သင့်အင်တာနက် ချိတ်ဆက်မှုသည် ပုံမှန်မဟုတ်ဘဲ နှေးနေပါသလား။\n\n၄င်းအကြောင်းအရာတို့ကို သိရှိရန် OONI Probe ကိုဖွင့်ပါ။ ရပြီ ကြိုတင်အသိပေးသည်။ OONI ဒေတာကို ပွင့်လင်းမြင်သာစွာ ထုတ်ဝေထားပြီး သင့်ကွန်ရက် အချက်အလက် များကိုလည်း ပါဝင်မည် ဖြစ်သည်။ @@ -11,14 +11,14 @@ နားလည်သည် ပိုမိုလေ့လာရန် လျှပ်တပြက် ဉာဏ်စမ်း - မှန် + မှန်သည် မှားသည် နောက်သို့ ဆက်လုပ်မည် မေးခွန်း ၁/၂ - တစ်စုံတစ်ယောက်သည် ကျွန်ုပ်၏အင်တာနက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နေပါက၊ ကျွန်ုပ်သည် OONI Probe ကို အသုံးပြုနေကြောင်း ၎င်းတို့ မြင်တွေ့ရမည် ဖြစ်သည်။ + တစ်စုံတစ်ယောက်သည် ကျွန်ုပ်၏ အင်တာနက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နေပါက၊ ကျွန်ုပ်သည် OONI Probe ကို အသုံးပြုနေကြောင်း ၎င်းတို့ မြင်တွေ့ရမည် ဖြစ်သည်။ သတိပေးချက် - OONI Probe သည် ကိုယ်ရေးလုံခြုံမှု ကိရိယာတစ်ခု မဟုတ်ပါ။ သင့် အင်တာနက် လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နေသူတိုင်းသည် သင်အသုံးပြုနေသည့် ဆော့ဖ်ဝဲလ်ကို သိပါလိမ့်မည်။ + OONI Probe သည် ကိုယ်ရေးလုံခြုံမှု ကိရိယာတစ်ခု မဟုတ်ပါ။ သင့် အင်တာနက် လုပ်ဆောင်ချက်များကို စောင့်ကြည့် နေသူတိုင်းသည် သင် အသုံးပြုနေသည့် ဆော့ဖ်ဝဲလ်ကို သိပါလိမ့်မည်။ မေးခွန်း ၂/၂ OONI Probe ကို ကျွန်ုပ်အသုံးပြုတိုင်း၊ ကျွန်ုပ် စုဆောင်းထားသော ကွန်ရက်ဒေတာကို အလိုအလျောက် ထုတ်ဝေပါမည်။ သတိပေးချက် @@ -28,7 +28,7 @@ ပျက်စီးမှု သတင်းပို့ခြင်း OONI Probe ပိုမိုကောင်းမွန်စေရန်အတွက် အက်ပ်သည် ကောင်းမွန်စွာ အလုပ်မလုပ်သည့်အခါ အမည်မသိ ပျက်စီးမှု အစီရင်ခံစာများကို စုဆောင်းလိုပါသည်။\n\nပျက်စီးမှု အစီရင်ခံစာများကို OONI ဖွံ့ဖြိုးတိုးတက်ရေး အဖွဲ့ထံ တင်သွင်းခြင်း လုပ်ငန်းတွင် သင် ပါဝင်လိုပါသလား။ ဟုတ်တယ် - မဟုတ်ပါ + မဟုတ်ဘူး နဂိုမူလ ဆက်တင်များ ကျွန်ုပ်တို့ ကောက်ယူစုဆောင်း၍ ဖြန့်ဝေသည် - နိုင်ငံကုဒ် (ဥပမာ - အီတလီအတွက် IT) @@ -84,7 +84,7 @@ စမ်းသပ်မှုများ ကွန်ရက်များ ဒေတာအသုံးပြုမှု - စမ်းသပ်မှုများ စစ်ထုတ်ရန် + စမ်းသပ်မှုများ စမ်းသပ်မှုအားလုံး ဝဘ်ဆိုဒ်များ Middleboxes @@ -93,19 +93,19 @@ ရှောင်တိမ်းခြင်း စမ်းသပ် လေ့လာနေဆဲ စမ်းသပ်မှု မရှိသေးပါ။ စမ်းသပ်မှုတစ်ခုကို လုပ်ဆောင် ကြည့်လိုက်ပါ။ - %1$s ပိတ်ဆို့ထားသည် - %1$s ပိတ်ဆို့ထားသည် - %1$s စမ်းသပ်ခဲ့သည် - %1$s စမ်းသပ်ခဲ့သည် + %1$s ခု ပိတ်ဆို့ထားသည် + %1$s ခု ပိတ်ဆို့ထားသည် + %1$s ကြိမ် စမ်းသပ်ခဲ့သည် + %1$s ကြိမ် စမ်းသပ်ခဲ့သည် စစ်ဆေး တွေ့ရှိခဲ့သည် ရှာမတွေ့ပါ မအောင်မြင်ပါ - %1$s ပိတ်ဆို့ထားသည် - %1$s ပိတ်ဆို့ထားသည် + %1$s ခု ပိတ်ဆို့ထားသည် + %1$s ခု ပိတ်ဆို့ထားသည် %1$s အသုံးပြုနိုင်သည် %1$s အသုံးပြုနိုင်သည် - %1$s ပိတ်ဆို့ထားသည် - %1$s ပိတ်ဆို့ထားသည် + %1$s ခု ပိတ်ဆို့ထားသည် + %1$s ခု ပိတ်ဆို့ထားသည် %1$s ရရှိနိုင်သည် %1$s ရရှိနိုင်သည် မပြည့်စုံသော ရလဒ် @@ -261,8 +261,8 @@ OpenVPN ချိတ်ဆက်မှုများ ပေါင်းစပ် ချိတ်ဆက်မှုများ ပိတ်ဆို့ထားသည် - %1$s ပိတ်ဆို့ထားသည် - %1$s ပိတ်ဆို့ထားသည် + %1$s ခု ပိတ်ဆို့ထားသည် + %1$s ခု ပိတ်ဆို့ထားသည် အိုကေ ဤစမ်းသပ်မှုသည် အစမ်းသဘော ဖြစ်သည်။ သတင်း @@ -298,7 +298,7 @@ အပ်လုဒ်လုပ်ခြင်း အောင်မြင်သည် ပျက်ကွက်မှု မှတ်တမ်းကို ပြသရန်\n အင်တာနက် ဆင်ဆာဖြတ်ခြင်းဆိုင်ရာ အပ်ဒိတ်များကို ရယူပါ။ - အရေးပေါ် ဆင်ဆာဖြတ်တောက်မှု ဖြစ်ရပ်များအတွင်း OONI Probe စမ်းသပ်မှုများကို လုပ်ဆောင်ရန် စိတ်ဝင်စားပါသလား။ သင့် အနီးရှိ အင်တာနက် ဆင်ဆာ ဖြတ်တောက်မှုကို ကျွန်ုပ်တို့ ကြားရသည့်အခါ အချက်အလက် သတင်း လက်ခံရရှိရန် အသိပေးချက်များကို ဖွင့်ပါ။ + အရေးပေါ် ဆင်ဆာဖြတ်တောက်မှု ဖြစ်ရပ်များအတွင်း OONI Probe စမ်းသပ်မှုများကို လုပ်ဆောင်ရန် စိတ်ဝင်စားပါသလား။ သင့် အနီးရှိ အင်တာနက်ဆင်ဆာ ဖြတ်တောက်မှုကို ကျွန်ုပ်တို့ ကြားရသည့်အခါ အချက်အလက် သတင်း လက်ခံရရှိရန် အသိပေးချက်များကို ဖွင့်ပါ။ စစ်ဆေးမှုများ၏ တိကျမှုကို မြှင့်တင်ရန်၊ ကျွန်ုပ်တို့သည် GPS ခွင့်ပြုချက်များ လိုအပ်ပါသည်။ OONI သည် သင့် GPS အနေအထား၏ ခန့်မှန်းခြေကိုသာ စုဆောင်း ပါမည်။ စမ်းသပ်မှုရလဒ်အားလုံးကို ဖျက်လိုပါသလား။ ဤစမ်းသပ်မှုကို ဖျက်လိုပါသလား။ @@ -406,7 +406,7 @@ စမ်းသပ်ကာလကို ကန့်သတ်မည် စမ်းသပ်မှုကာလ စမ်းသပ်ရန် ဝဘ်ဆိုဒ် အမျိုးအစားများ - အမျိုးအစား %1$s ကို ဖွင့်ထားသည် + အမျိုးအစား %1$s ခု ကို ဖွင့်ထားသည် တည်းဖြတ်မည် အားလုံးကို မရွေးချယ်ရန်\n အားလုံးကို ရွေးချယ်မည်\n @@ -456,7 +456,7 @@ တင်နေပါသည်... မမျှော်လင့်ထားသော ပြဿနာ ဖြစ်ပေါ်ခဲ့သည်။ ဤစာမျက်နှာကို ပြန်လည်စတင်ပါ။ သင်သည် OONI Probe စမ်းသပ်မှု တစ်ခုကို လုပ်ဆောင်ပါတော့မည်။ - %1$s URL များ + URL %1$s ခု စမ်းသပ်မှု အမည် စမ်းသပ်မှု အသေးစိတ် စမ်းမည် diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 5c2d54de9..d02b4fea4 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -3,20 +3,20 @@ ONNI Probe OONI Probe là gì? Ứng dụng này để đo lường kiểm duyệt internet\n\nCác trang web và các ứng dụng mạng xã hội có bị chặn không? Kết nối internet của bạn có bị chậm bất thường không?\n\nHãy chạy ứng dụng OONI Probe để tìm hiểu! - Tôi đã hiểu + Hiểu rồi Chú ý! Dữ liệu của OONI được công bố công khai, bao gồm thông tin về mạng của bạn. Bất cứ ai giám sát hoạt động internet của bạn (ví dụ như chính phủ hay nhà mạng) sẽ biết bạn đang chạy OONI Probe. - Bạn có thể kiểm tra các trang web bị chặn (hoặc chọn trang bất kì để kiểm tra) - Tôi đã hiểu + Bạn có thể kiểm tra các trang web bị chặn (hoặc chọn bất cứ trang nào để kiểm tra) + Tôi hiểu Tìm hiểu thêm - Pop Quiz + Đố Nhanh Đúng Sai Quay lại Tiếp tục Câu hỏi 1/2 - Nếu có ai đó đang giám sát hoạt động internet của tôi, họ sẽ có thể biết tôi đang chạy ứng dụng OONI Probe. + Nếu có ai đó đang giám sát hoạt động internet của tôi, họ sẽ biết tôi đang chạy ứng dụng OONI Probe. Cảnh báo ONNI Probe không phải công cụ có tính bảo mật cá nhân. Bất cứ ai đang giám sát hoạt động internet của bạn sẽ biết được bạn đang chạy những phần mềm nào. Câu hỏi 2/2 @@ -29,20 +29,20 @@ Để cải thiện OONI Probe, chúng tôi muốn thu thập các báo cáo sự cố ẩn danh khi ứng dụng không hoạt động bình thường.\n\nBạn có muốn chọn gửi báo cáo sự cố cho nhóm phát triển OONI không? Không - Cài đặt mặc định + Thiết đặt mặc định Chúng tôi thu thập và công bố: - Mã quốc gia (ví dụ IT đại diện cho Italy) + Mã quốc gia (ví dụ VN cho Việt Nam) Thông tin mạng (bao gồm Số hệ thống tự trị - ASN) - Thời gian và ngày kiểm tra - Chúng tôi luôn cố gắng để không công bố địa chỉ IP của bạn hay bất kỳ thông tin tiềm tàng nào khác nhằm nhận dạng cá nhân.\n\nTìm hiểu thêm thông qua [Chính sách dữ liệu của OONI] (https://ooni.org/about/data-policy/). - Bằng việc nhấn \"OK\", bạn sẽ chia sẻ báo cáo sự cố để giúp chúng tôi cải thiện OONI Probe. + Ngày Giờ kiểm tra + Chúng tôi luôn cố gắng để không công bố địa chỉ IP của bạn hay bất kỳ thông tin nào khác có thể nhận dạng cá nhân.\n\nTìm hiểu thêm thông qua [Chính sách dữ liệu của OONI] (https://ooni.org/about/data-policy/). + Khi nhấn \"OK\", bạn đồng ý chia sẻ báo cáo sự cố để giúp chúng tôi cải thiện OONI Probe. Bắt đầu Thay đổi mặc định Bảng tóm tắt Chạy - N/A + Không có Chạy - Lần kiểm tra gần đây nhất + Lần kiểm tra chót: Ước lượng: Chọn trang web Đang chạy: @@ -52,53 +52,53 @@ Tính toán ETA Hiển thị Nhật ký Đóng Nhật ký - Đang dừng kiểm tra + Dừng kiểm tra Đang hoàn tất các bài kiểm tra dở dang, vui lòng chờ đợi.... Proxy đang sử dụng Chạm vào thẻ để biết thêm chi tiết ~%1$s Kiểm tra việc chặn các trang web - Kiểm tra xem các trang web có bị chặn không bằng cách sử dụng [Kiểm tra Web Connectivity] của OONI (https://ooni.org/nettest/web-connectivity/).\n\nMỗi khi nhấn Chạy, bạn sẽ kiểm tra các trang web khác nhau từ danh sách [toàn cầu] của Citizen Lab (https://github.com/citizenlab/test-lists/blob/master/lists/global.csv) và danh sách [quốc gia cụ thể] (https://github.com/citizenlab/test-lists/tree/master/lists).\n\nĐể chọn trang web bất kì và kiểm tra, hãy nhấn vào nút Chọn trang web hoặc chọn các danh mục trang web ở phần cài đặt.\n\nKiểm tra này cho biết các trang web có bị chặn bởi các phương thức giả mạo DNS, chặn TCP/IP hay bởi một proxy HTTP minh bạch không.\n\nKết quả của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). - Kiểm tra xem các trang web có bị chặn không bằng cách sử dụng [Kiểm tra Web Connectivity] của OONI (https://ooni.org/nettest/web-connectivity/).\n\nBạn sẽ kiểm tra các trang web khác nhau từ danh sách [toàn cầu] của Citizen Lab (https://github.com/citizenlab/test-lists/blob/master/lists/global.csv) và danh sách [quốc gia cụ thể] (https://github.com/citizenlab/test-lists/tree/master/lists).\n\nKiểm tra này cho biết các trang web có bị chặn bởi các phương thức giả mạo DNS, chặn TCP / IP hay bởi một proxy HTTP minh bạch hay không.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). + Kiểm tra xem các trang web có bị chặn không bằng cách sử dụng [Kiểm tra Kết nối Web] của OONI (https://ooni.org/nettest/web-connectivity/).\n\nMỗi khi nhấn Chạy, bạn sẽ kiểm tra các trang web khác nhau từ danh sách [toàn cầu] của Citizen Lab (https://github.com/citizenlab/test-lists/blob/master/lists/global.csv) và danh sách [quốc gia cụ thể] (https://github.com/citizenlab/test-lists/tree/master/lists).\n\nĐể chọn trang bạn muốn kiểm tra, hãy nhấn vào nút Chọn trang web hoặc chọn các danh mục trang web ở phần cài đặt.\n\nKiểm tra này cho biết các trang web có bị chặn bởi các phương thức sửa DNS trái phép, chặn TCP/IP hay bởi một proxy HTTP minh bạch không.\n\nKết quả của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). + Kiểm tra xem các trang web có bị chặn không bằng cách sử dụng [Kiểm tra Kết nối Web] của OONI (https://ooni.org/nettest/web-connectivity/).\n\nBạn sẽ kiểm tra các trang web khác nhau từ danh sách [toàn cầu] của Citizen Lab (https://github.com/citizenlab/test-lists/blob/master/lists/global.csv) và danh sách [quốc gia cụ thể] (https://github.com/citizenlab/test-lists/tree/master/lists).\n\nKiểm tra này cho biết các trang web có bị chặn bởi các phương thức sửa DNS trái phép, chặn TCP / IP hay bởi một proxy HTTP minh bạch hay không.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/) và [OONI API] (https://api.ooni.io/). Kiểm tra tốc độ và hiệu suất mạng của bạn - Đo tốc độ và hiệu suất mạng của bạn bằng cách sử dụng kiểm tra [NDT] (https://ooni.org/nettest/ndt/).\n\nĐo hiệu suất phát trực tuyến video bằng bài kiểm tra [DASH] (https://ooni.org/nettest/dash/).\n\nCác bài kiểm tra này sử dụng dữ liệu tùy thuộc vào tốc độ mạng của bạn.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/).\n\nTuyên bố miễn trừ trách nhiệm: Những kiểm tra này dựa trên máy chủ của bên thứ ba. Do đó, chúng tôi không thể đảm bảo rằng địa chỉ IP của bạn sẽ không bị thu thập. - Bằng cách chạy các bài kiểm tra này, bạn sẽ:\n\n- Đo tốc độ và hiệu suất mạng của bạn (kiểm tra [NDT] (https://ooni.org/nettest/ndt/))\n- Đo hiệu suất phát trực tuyến video (kiểm tra [DASH] (https://ooni.org/nettest/dash/))\n- Kiểm tra sự hiện diện của [công nghệ middlebox] (https://ooni.org/support/glossary/#middlebox) trên mạng của bạn qua các kiểm tra ([HTTP Invalid Request Line] (https://ooni.org/nettest/http-invalid -request-line /) và [HTTP Header Field Manipulation] (https://ooni.org/nettest/http-header-field-manipulation/) )\n\nCác bài kiểm tra này sử dụng dữ liệu tùy thuộc vào tốc độ mạng của bạn.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/) và [OONI API] (https://api.ooni.io/).\n\n** Tuyên bố miễn trừ trách nhiệm: ** Các bài kiểm tra [NDT] (https://ooni.org/nettest/ndt/) và [DASH] (https://ooni.org/nettest/dash/) được thực hiện trên các máy chủ của bên thứ ba được cung cấp bởi [Measurement Lab (M-Lab)] (https://www.measurementlab.net/). Nếu bạn chạy các bài kiểm tra này, M-Lab sẽ thu thập và công bố địa chỉ IP của bạn (cho mục đích nghiên cứu), cho dù cài đặt OONI Probe của bạn như thế nào. Tìm hiểu thêm về quản trị dữ liệu của M-Lab thông qua [tuyên bố về quyền riêng tư] (https://www.measurementlab.net/privacy/). + Đo tốc độ và hiệu suất mạng của bạn bằng cách sử dụng kiểm tra [NDT] (https://ooni.org/nettest/ndt/).\n\nĐo hiệu suất phát trực tuyến video bằng bài kiểm tra [DASH] (https://ooni.org/nettest/dash/).\n\nCác bài kiểm tra này dùng dữ liệu tùy thuộc vào tốc độ mạng của bạn.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/).\n\nTuyên bố giới hạn trách nhiệm: Những kiểm tra này dựa trên máy chủ của bên thứ ba. Do đó, chúng tôi không thể đảm bảo rằng địa chỉ IP của bạn sẽ không bị thu thập. + Bằng cách chạy các bài kiểm tra này, bạn sẽ:\n\n- Đo tốc độ và hiệu suất mạng của bạn (kiểm tra [NDT] (https://ooni.org/nettest/ndt/))\n- Đo hiệu suất phát trực tuyến video (kiểm tra [DASH] (https://ooni.org/nettest/dash/))\n- Kiểm tra sự hiện diện của [công nghệ middlebox] (https://ooni.org/support/glossary/#middlebox) trên mạng của bạn qua các kiểm tra ([HTTP Invalid Request Line] (https://ooni.org/nettest/http-invalid -request-line /) và [HTTP Header Field Manipulation] (https://ooni.org/nettest/http-header-field-manipulation/) )\n\nCác bài kiểm tra này sử dụng dữ liệu tùy thuộc vào tốc độ mạng của bạn.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/) và [OONI API] (https://api.ooni.io/).\n\n** Tuyên bố giới hạn trách nhiệm: ** Các bài kiểm tra [NDT] (https://ooni.org/nettest/ndt/) và [DASH] (https://ooni.org/nettest/dash/) được thực hiện trên các máy chủ của bên thứ ba được cung cấp bởi [Measurement Lab (M-Lab)] (https://www.measurementlab.net/). Nếu bạn chạy các bài kiểm tra này, M-Lab sẽ thu thập và công bố địa chỉ IP của bạn (cho mục đích nghiên cứu), cho dù cài đặt OONI Probe của bạn như thế nào. Tìm hiểu thêm về quản trị dữ liệu của M-Lab thông qua [tuyên bố về quyền riêng tư] (https://www.measurementlab.net/privacy/). Phát hiện các middlebox trong mạng của bạn - Nhà mạng thường sử dụng các thiết bị mạng (middlebox) cho các mục đích mạng khác nhau (ví dụ như bộ nhớ đệm). Đôi khi những middlebox này được sử dụng để thực hiện kiểm duyệt và/ hoặc giám sát internet.\n\nTìm các middlebox trong mạng của bạn bằng cách kiểm tra [HTTP Invalid Request Line] của OONI (https://ooni.org/nettest/http-invalid-request-line/) và kiểm tra [HTTP Header Field Manipulation] (https://ooni.org/nettest/http-header-field-manipulation/) .\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). - Kiểm tra việc chặn các ứng dụng nhắn tin tức thời + Nhà mạng thường sử dụng các thiết bị mạng (middlebox) cho các mục đích mạng khác nhau (ví dụ như bộ nhớ đệm). Đôi khi những middlebox này được sử dụng để thực hiện kiểm duyệt và/ hoặc giám sát internet.\n\nTìm các middlebox trong mạng của bạn bằng cách kiểm tra [HTTP Invalid Request Line] của OONI (https://ooni.org/nettest/http-invalid-request-line/) và kiểm tra [HTTP Header Field Manipulation] (https://ooni.org/nettest/http-header-field-manipulation/) .\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). + Kiểm tra việc chặn các ứng dụng tin nhắn nhanh Kiểm tra [WhatsApp] (https://ooni.org/nettest/whatsapp/), [Facebook Messenger] (https://ooni.org/nettest/facebook-messenger/), [Telegram] (https://ooni .org/nettest/telegram/) và [Signal] (https://ooni.org/nettest/signal) có bị chặn không.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/world/) và [OONI API] (https://api.ooni.io/). - Kiểm tra việc chặn các công cụ vượt kiểm duyệt + Kiểm tra việc chặn các công cụ vượt thoát kiểm duyệt Kiểm tra [Psiphon] (https://ooni.org/nettest/psiphon/), [Tor] (https://ooni.org/nettest/tor/) hay [RiseupVPN] (https://ooni.org/nettest/roseupvpn/) có bị chặn không.\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/) và [OONI API] (https://api.ooni.io/). Chạy các bài kiểm tra thử nghiệm mới Chạy các bài kiểm tra thử nghiệm mới sau đây do nhóm OONI phát triển:\n%1$s\n\nKết quả kiểm tra của bạn sẽ được công bố trên [OONI Explorer] (https://explorer.ooni.org/) và [OONI API] (https://api.ooni.io/). - Các bài kiểm tra sau đây sẽ chỉ được chạy khi thực hiện kiểm tra tự động: - Disabled Tests + Các bài kiểm tra sau đây chỉ được chạy khi thực hiện kiểm tra tự động: + Kiểm tra bị tắt Gbit/giây Mbit/giây kbit/giây mili giây - Không có sẵn - Không có thông tin + Không có + Không rõ Kết quả kiểm tra Kết quả kiểm tra Các bài kiểm tra Mạng - Sử dụng dữ liệu - Kiểm tra bộ lọc - Tất cả các bài kiểm tra + Lượng dữ liệu dùng + Sàng lọc Kiểm tra + Tất cả kiểm tra Trang web Các middlebox Hiệu suất - Nhắn tin tức thời - Vượt qua kiểm duyệt Internet + Tin Nhắn Nhanh + Vượt thoát kiểm duyệt Thử nghiệm - Chưa có bài kiểm tra nào được chạy. Hãy chạy thử 1 bài kiểm tra! + Chưa có bài kiểm tra nào được chạy. Hãy chạy thử một bài kiểm tra! %1$s đã bị chặn %1$s đã bị chặn %1$s đã được kiểm tra %1$s đã được kiểm tra - Đã phát hiện - Chưa phát hiện + Tìm thấy + Không tìm thấy Thất bại %1$s đã bị chặn %1$s đã bị chặn @@ -108,23 +108,23 @@ %1$s đã bị chặn %1$s có sẵn %1$s có sẵn - Kết quả chưa hoàn thiện + Kết quả chưa đầy đủ Lỗi Lỗi trong quá trình đo lường Kết quả không được tải lên - Ngày & Thời gian + Ngày & Giờ Mạng Quốc gia - Sử dụng dữ liệu - Tổng thời gian chạy + Lượng dữ liệu dùng + Tổng cộng thời gian chạy WiFi Dữ liệu di động Không có internet Thất bại Đã kiểm tra Đã kiểm tra - Đã khóa - Đã khóa + Đã bị chặn + Đã bị chặn Trang web Trang web Có thể truy cập @@ -134,21 +134,21 @@ Tải lên Tải về Ping - Đã phát hiện - Chưa phát hiện + Tìm thấy + Không tìm thấy Thất bại Đã kiểm tra Đã kiểm tra - Đã khóa - Đã khóa + Đã bị chặn + Đã bị chặn Có thể truy cập Có thể truy cập Ứng dụng Các ứng dụng Đã kiểm tra Đã kiểm tra - Đã khóa - Đã khóa + Đã bị chặn + Đã bị chặn Đang hoạt động Đang hoạt động Công cụ @@ -159,7 +159,7 @@ Dữ liệu Sao chép URL của Explorer Chia sẻ URL của Explorer - Sao chép vào Clipboard + Sao chép vào Bảng ghi tạm Hiển thị trong OONI Explorer Thất bại Bạn có thể thử chạy lại bài kiểm tra này @@ -167,12 +167,12 @@ Tìm hiểu cách hoạt động của bài kiểm tra này [tại đây] (%1$s). Có thể truy cập %1$s có thể truy cập được - Có khả năng đã bị chặn - %1$s có thể bị chặn bởi %2$s.\n\nLưu ý: Có thể xảy ra hiện tượng dương tính giả. Tìm hiểu thêm [tại đây] (https://ooni.org/support/faq/#what-are-false-pososystem) - Vượt kiểm duyệt - Giả mạo DNS + Có lẻ đã bị chặn + %1$s có lẻ bị chặn bởi %2$s.\n\nLưu ý: Kết quả này có thể không trúng (hiện tượng dương tính giả). Tìm hiểu thêm [tại đây] (https://ooni.org/support/faq/#what-are-false-pososystem) + Vượt thoát kiểm duyệt + **Sửa DNS trái phép** ** Chặn dựa trên TCP/IP ** - ** Chặn HTTP (có thể có một trang chặn) ** + ** Chặn HTTP (trang chặn được gửi ra) ** ** Chặn HTTP (yêu cầu HTTP không thành công) ** Ứng dụng trên điện thoại OK @@ -184,9 +184,9 @@ OK Thất bại Đang hoạt động - Bài kiểm tra này đã kết nối thành công với các endpoint, dịch vụ đăng ký và giao diện web của WhatsApp (web.whatsapp.com). - Có khả năng bị chặn - WhatsApp có thể đã bị chặn. + Bài kiểm tra này đã kết nối thành công với các điểm cuối, dịch vụ đăng ký và giao diện web của WhatsApp (web.whatsapp.com). + Có lẻ bị chặn + WhatsApp dường như bị chặn. Ứng dụng trên điện thoại OK Thất bại @@ -194,9 +194,9 @@ OK Thất bại Đang hoạt động - Bài kiểm tra này đã kết nối thành công với các endpoint và giao diện web của Telegram (web.telegram.org). - Có khả năng bị chặn - Telegram có thể đã bị chặn + Bài kiểm tra này đã kết nối thành công với các điểm cuối và giao diện web của Telegram (web.telegram.org). + Có lẻ bị chặn + Telegram dường như bị chặn Các kết nối TCP OK Thất bại @@ -204,21 +204,21 @@ OK Thất bại Đang hoạt động - Bài kiểm tra này đã kết nối thành công với các endpoint của Facebook và xử lý các địa chỉ IP của Facebook. - Có khả năng bị chặn - Facebook Messenger có thể đã bị chặn. - Có khả năng bị chặn - Signal có thể đã bị chặn. + Bài kiểm tra này đã kết nối thành công với các điểm cuối của Facebook và lý giải đến các địa chỉ IP của Facebook. + Có lẻ bị chặn + Facebook Messenger dường như bị chặn. + Có lẻ bị chặn + Signal dường như bị chặn. Đang hoạt động - Bài kiểm tra này đã kết nối thành công với các endpoint của Signal. + Bài kiểm tra này đã kết nối thành công với các điểm cuối của Signal. Không phát hiện middlebox Không phát hiện bất thường trên mạng khi giao tiếp với máy chủ của chúng tôi. - Giả mạo mạng - Lưu lượng mạng đã bị thao túng khi liên lạc với các máy chủ kiểm soát của chúng tôi.\n\nĐiều này nghĩa là có thể có một middlebox trong mạng của bạn, có thể nhằm kiểm duyệt và/hoặc giám sát. + Sửa đổi mạng trái phép + Lưu lượng mạng đã bị thay đổi trái phép khi liên lạc với các máy chủ kiểm soát của chúng tôi.\n\nĐiều này nghĩa là có thể có một middlebox trong mạng của bạn, có thể nhằm kiểm duyệt và/hoặc giám sát. Không phát hiện middlebox Không phát hiện bất thường trên mạng khi giao tiếp với máy chủ của chúng tôi. - Giả mạo mạng - Lưu lượng mạng đã bị thao túng khi liên lạc với các máy chủ kiểm soát của chúng tôi.\n\nĐiều này nghĩa là có thể có một middlebox trong mạng của bạn, có thể nhằm để kiểm duyệt và/hoặc giám sát. + Sửa đổi mạng trái phép + Lưu lượng mạng đã bị thay đổi trái phép khi liên lạc với các máy chủ kiểm soát của chúng tôi.\n\nĐiều này nghĩa là có thể có một middlebox trong mạng của bạn, có thể nhằm để kiểm duyệt và/hoặc giám sát. Bạn đã gửi Bạn đã nhận Tải lên @@ -232,35 +232,35 @@ MSS Thời gian chờ Bạn có thể phát trực tiếp lên đến %1$s mà không bị gián đoạn - Trung vị Tốc độ bit + Tốc độ bit trung bình Hoãn phát lại - Có khả năng bị chặn + Có lẻ bị chặn Đang hoạt động - [Psiphon](https://psiphon.ca/) có thể đã bị chặn. - Chúng tôi đã bootstrap thành công kết nối Psiphon. Điều này có nghĩa là [Psiphon] (https://psiphon.ca/) sẽ hoạt động. - Thời gian Bootstrap + [Psiphon](https://psiphon.ca/) dường như bị chặn. + Chúng tôi đã khởi động thành công kết nối Psiphon. Điều này có nghĩa là [Psiphon] (https://psiphon.ca/) sẽ hoạt động. + Thời gian Khởi động %1$s giây - Có khả năng bị chặn + Có lẻ bị chặn Đang hoạt động - [Tor](https://www.torproject.org/) có thể đã bị chặn. - Chúng tôi đã kết nối thành công với cầu chuyển tiếp và/hoặc quản lý thư mục mặc định của Tor. Điều này có nghĩa là [Tor] (https://www.torproject.org/) sẽ hoạt động. + [Tor](https://www.torproject.org/) dường như bị chặn. + Chúng tôi đã kết nối thành công với cầu Tor mặc định và/hoặc danh bạ chính thức của Tor. Điều này có nghĩa là [Tor] (https://www.torproject.org/) sẽ hoạt động. Cầu chuyển tiếp mặc định %1$s/%2$s OK - Quản lý thư mục + Danh bạ Chính thức %1$s/%2$s OK Tên - Địa chỉ nhà + Địa chỉ Loại Kết nối Giao thức bắt tay - Có khả năng đã bị chặn + Có lẻ bị chặn Đang hoạt động - [RiseupVPN](https://riseup.net/vpn) có thể đã bị chặn. - Chúng tôi đã kết nối thành công với máy chủ bootstrap của RiseupVPN và các cổng VPN. Điều này có nghĩa là [RiseupVPN] (https://riseup.net/vpn) sẽ hoạt động. - Máy chủ Bootstrap + [RiseupVPN](https://riseup.net/vpn) dường như bị chặn. + Chúng tôi đã kết nối thành công với máy chủ khởi động của RiseupVPN và các cổng VPN. Điều này có nghĩa là [RiseupVPN] (https://riseup.net/vpn) sẽ hoạt động. + Máy chủ Khởi động Các kết nối OpenVPN Các kết nối bắc cầu - Đã khóa + Đã chặn %1$s đã bị chặn %1$s đã bị chặn OK @@ -273,17 +273,17 @@ Xóa Lỗi Thử lại - Ổn đấy + Rất tốt Không, cảm ơn Không phải bây giờ - Vẫn chạy tiếp + Cứ chạy Tắt VPN Luôn chạy Không thể chạy bài kiểm tra. Vui lòng kiểm tra lại kết nối internet của bạn. Không thể tải danh sách URL. Vui lòng thử lại. Vui lòng đợi các bài kiểm tra đang chạy kết thúc trước khi bắt đầu một bài kiểm tra mới. - Cần cài đặt cho phép thông báo. Vui lòng bật thông báo trong Cài đặt của điện thoại sau đó bật thông báo trong ứng dụng OONI Probe của bạn. - Đến phần Cài đặt + Cần cho phép thông báo. Vui lòng bật thông báo trong Thiết Đặt của điện thoại sau đó bật thông báo trong ứng dụng OONI Probe của bạn. + Vào phần Thiết Đặt Màn hình bị khóa khi bài kiểm tra đang chạy Bạn cần kết nối với Internet để tải về các dữ liệu thô về đo lường Kết quả không được tải lên @@ -299,45 +299,45 @@ Hiển thị nhật ký lỗi Nhận thông tin cập nhật về kiểm duyệt internet Bạn quan tâm đến việc chạy kiểm tra OONI Probe trong các tình huống kiểm duyệt khẩn cấp? Bật thông báo để nhận tin nhắn khi chúng tôi biết có kiểm duyệt internet ở gần bạn. - Để cải thiện độ chính xác của các bài kiểm tra, chúng tôi cần có quyền truy cập GPS. OONI sẽ chỉ thu thập thông tin gần đúng về vị trí GPS của bạn. + Để cải thiện độ chính xác của các bài kiểm tra, chúng tôi cần có quyền truy cập GPS. OONI sẽ chỉ thu thập thông tin khái quát về vị trí GPS của bạn. Bạn có muốn xóa tất cả các kết quả kiểm tra không? Bạn có muốn xóa bài kiểm tra này không? Vui lòng cho phép chạy ít nhất một bài kiểm tra - Vui lòng chỉ điền các chữ số vào trường này. + Xin chỉ điền số vào khung này. Chạy lại bài kiểm tra Bài kiểm tra này không thành công. Chạy lại bài kiểm tra? Bạn chuẩn bị kiểm tra lại %1$s trang web. Chạy URL của bạn sẽ không được lưu khi bạn rời khỏi màn hình này. Bạn có chắc chắn muốn rời khỏi màn hình này không? - Bật tải lên thủ công? - Cài đặt này cho phép bạn tải lên thủ công các kết quả đo lường chưa được công bố. - Cho phép + Bật cách Tự Tải Lên ? + Cài đặt này cho phép bạn tự mình tải lên các kết quả đo lường chưa được công bố. + Bật mở Không, cảm ơn Tải lên thất bại Chúng tôi không thể tải lên %1$s / %2$s kết quả đo lường. Nhật ký lỗi đã được chia sẻ với các nhà phát triển OONI. - Không tìm thấy tệp nhật ký + Không tìm thấy tập tin nhật ký Không tìm thấy URL hợp lệ JSON trống Bạn có muốn tạm dừng bài kiểm tra này không? - Việc này sẽ làm gián đoạn bài kiểm tra hiện từ thời điểm này. + Việc này sẽ làm gián đoạn bài kiểm tra từ thời điểm này. Bạn có muốn chạy tự động các bài kiểm tra này không? Bằng việc bật kiểm tra tự động, bạn sẽ đóng góp thường xuyên các kết quả đo lường cho OONI. - Vui lòng cho phép ứng dụng chạy trên nền. - Nhắc lại tôi về sau + Vui lòng cho phép ứng dụng chạy trên nền sau. + Nhắc lại tôi sau Đã sao chép vào clipboard Chưa được tải lên Tải lên Một số chưa được tải lên Tải lên tất cả Trang web - Nhắn tin tức thời + Tin Nhắn Nhanh Các middlebox Hiệu suất - Vượt qua kiểm duyệt Internet + Vượt thoát kiểm duyệt Thử nghiệm Kiểm tra HTTP Invalid Request Line Kiểm tra HTTP Header Field Manipulation - Kiểm tra Web Connectivity + Kiểm tra Kết Nối Web Kiểm tra tốc độ NDT Kiểm tra phát trực tuyến DASH Kiểm tra WhatsApp @@ -347,16 +347,16 @@ Kiểm tra Tor Kiểm tra RiseupVPN Kiểm tra Signal - Cài đặt - Thời gian bạn đặt cho quá trình kiểm tra quá ngắn, + Thiết đặt + Thời lượng bạn chọn cho quá trình kiểm tra quá ngắn, Giới thiệu về OONI - Quan sát mở về can thiệp mạng (OONI) là một dự án phần mềm miễn phí thuộc Dự án Tor nhằm mục đích tăng cường tính minh bạch của việc kiểm duyệt internet trên toàn thế giới.\n\nKể từ năm 2012, cộng đồng OONI toàn cầu đã mở rộng mạng lưới tại hơn 200 quốc gia. Một số các kết quả đo lường này là bằng chứng về sự kiểm duyệt internet. - Biết thêm + Đài Quan Sát Mở về Can Thiệp Mạng (OONI) là một dự án phần mềm miễn phí thuộc Dự án Tor nhằm mục đích tăng cường tính minh bạch của việc kiểm duyệt internet trên toàn thế giới.\n\nKể từ năm 2012, cộng đồng OONI toàn cầu đã mở rộng mạng lưới tại hơn 200 quốc gia. Một số các kết quả đo lường này là bằng chứng về sự kiểm duyệt internet. + Tìm hiểu thêm Blog Báo cáo Chính sách Dữ liệu của OONI Thông báo - Được bật lên + Bật lên Thông báo khi bài kiểm tra hoàn tất Bài đăng mới Kiểm tra tự động @@ -368,24 +368,24 @@ Khi bật kiểm tra tự động, các bài kiểm tra OONI Probe sẽ tự động chạy nhiều lần mỗi ngày. Kết quả kiểm tra của bạn sẽ tự động được xuất bản trên OONI Explorer: https://explorer.ooni.org/\n\nQuan trọng: Nếu bạn bật VPN, OONI Probe sẽ không tự động chạy kiểm tra. Vui lòng tắt VPN của bạn để kiểm tra OONI Probe tự động. Tìm hiểu thêm: https://ooni.org/support/faq/#can-i-run-ooni-probe-over-a-vpn Chia sẻ Tự động công bố các kết quả - Tải lên thủ công kết quả + Tự Tải Lên Kết Quả Bao gồm thông tin mạng - Bao gồm vị trí địa lý gần đúng + Bao gồm vị trí địa lý ước lượng Bao gồm địa chỉ IP của tôi Bao gồm Mã quốc gia - Thông tin này (ví dụ: IT là viết tắt của Italia) là bắt buộc để xác định quốc gia mà các đo lường được thu thập. Bạn có chắc chắn muốn tắt tùy chọn này không? + Thông tin này (ví dụ: VN là viết tắt của Việt Nam) cần có để xác định quốc gia mà các đo lường được thu thập. Bạn có chắc chắn muốn tắt tùy chọn này không? Bằng việc công bố kết quả, bạn đang góp phần tăng cường tính minh bạch trong can thiệp mạng và hỗ trợ cộng đồng OONI.\n\nThông tin mạng (ví dụ Số hệ thống tự trị - ASN) là bắt buộc để xác định Nhà cung cấp mạng - Các tùy chọn kiểm tra - Những gì bạn cấu hình thông qua cài đặt kiểm tra ở trên (ví dụ: tắt kiểm tra WhatsApp) sẽ áp dụng cho các bài kiểm tra chạy theo cách thủ công, cũng như các bài kiểm tra chạy tự động (khi kiểm tra tự động được bật). + Tùy chọn kiểm tra + Những gì bạn cấu hình thông qua thiết đặt kiểm tra ở trên (ví dụ: tắt kiểm tra WhatsApp) sẽ áp dụng cho các bài kiểm tra chạy theo cách thủ công, cũng như các bài kiểm tra chạy tự động (khi kiểm tra tự động được bật). Bài kiểm tra dài - Chạy bài kiểm tra dài ở foreground? + Chạy bài kiểm tra dài ở nền trước? Riêng tư Gửi báo cáo sự cố Nâng cao - Chế độ tối - Nhật ký khắc phục lỗi + Màn hình tối + Nhật ký gỡ lỗi Xem nhật kí gần đây - Cài đặt Ngôn ngữ + Thiết đặt Ngôn ngữ Chọn Ngôn Ngữ Luôn sử dụng domain fronting Backend proxy của OONI @@ -404,23 +404,23 @@ Sử dụng Psiphon thay cho proxy tùy chỉnh Bạn không thể sử dụng OONI Probe? Hãy thử bật [Psiphon] (https://psiphon.ca/) để vượt qua kiểm duyệt lên OONI Probe. Hoặc, bạn có thể sử dụng proxy tùy chỉnh. Giới hạn thời lượng kiểm tra - Thời gian kiểm tra - Các danh mục trang web để kiểm tra - %1$s danh mục đã bật + Thời lượng kiểm tra + Thể loại web để kiểm tra + %1$s thể loại đã bật mở Chỉnh sửa Bỏ chọn tất cả Chọn Tất cả Lưu Thay đổi chưa được lưu - Bạn đã thực hiện một số thay đổi đối với các danh mục đã bật. Bạn có muốn lưu lại không? + Bạn đã thực hiện một số thay đổi đối với các thể loại đã bật mở. Bạn có muốn lưu lại không? Lưu - Bỏ qua + Hủy bỏ Chọn các trang web để kiểm tra URL Không có URL nào được nhập Chạy Thêm trang web - Tải từ biểu mẫu + Nạp vào từ biểu mẫu Số lượng trang web được thử nghiệm (0 có nghĩa là tất cả) Kiểm tra WhatsApp Kiểm tra Telegram @@ -440,35 +440,35 @@ Kiểm tra Tor Kiểm tra RiseupVPN Cảnh báo khi VPN được sử dụng - Gửi email để hỗ trợ + Gửi email đến hỗ trợ Vui lòng mô tả vấn đề bạn đang gặp phải: - Vui lòng gửi email đến bug@openobservatory.org kèm theo thông tin về ứng dụng và phiên bản iOS. Nhấn vào \"Sao chép vào clipboard\" bên dưới để sao chép địa chỉ email của chúng tôi. + Vui lòng gửi email đến bugs@openobservatory.org kèm theo thông tin về ứng dụng và phiên bản iOS. Nhấn vào \"Sao chép vào Bảng ghi tạm\" bên dưới để sao chép địa chỉ email của chúng tôi. Ngôn ngữ hiện tại của ứng dụng là %1$s Ngôn ngữ - Sử dụng bộ nhớ - Bộ nhớ đã sử dụng + Lượng lưu trữ sử dụng + Lượng lưu trữ đã dùng Xóa Xoá Bạn chuẩn bị xóa tất cả các kết quả đo lường OONI khỏi thiết bị của mình. Nếu được tải lên, những kết quả này sẽ có trên [OONI Explorer] (https://explorer.ooni.org) Đã chạy xong Dừng kiểm tra - Thử tính năng mirror - Đang tải... - Đã xảy ra lỗi không mong muốn. Vui lòng tải lại trang này. + Thử đối xứng + Đang nạp... + Đã xảy ra lỗi bất ngờ. Vui lòng nạp lại trang này. Bạn chuẩn bị chạy bài kiểm tra OONI Probe. %1$s URL Tên bài kiểm tra Thông tin về bài kiểm tra Chạy - Hết hạn + Quá hạn Bạn cần cài đặt phiên bản mới hơn của OONI Probe để chạy bài kiểm tra này. Cập nhật Đóng Thông số không hợp lệ Liên kết chạy OONI không đúng định dạng hoặc ứng dụng của bạn chưa được cập nhật. - Bạn sẽ kiểm tra một mẫu trang web ngẫu nhiên. + Bạn sẽ kiểm tra một số trang web ngẫu nhiên. Vui lòng đợi cho bài kiểm tra hoàn thành trước khi nhấn vào liên kết chạy OONI. - Chất kích thích và Rượu + Ma túy và Rượu Tôn giáo Nội dung khiêu dâm Trang phục khêu gợi @@ -481,13 +481,13 @@ Giáo dục giới tính Y tế công cộng Cờ bạc - Các công cụ vượt kiểm duyệt + Công cụ vượt thoát kiểm duyệt Hẹn hò trực tuyến Mạng xã hội LGBTQ+ - Chia sẻ file - Các công cụ lấy cắp dữ liệu - Các công cụ truyền thông + Chia sẻ tập tin + Công cụ lấy cắp dữ liệu + Công cụ truyền thông Chia sẻ truyền thông Dịch vụ lưu trữ web và viết blog Công cụ tìm kiếm @@ -499,11 +499,11 @@ Nội dung kiểm soát Tổ chức liên chính phủ Nội dung khác - Sử dụng và mua bán chất kích thích và rượu + Sử dụng và mua bán ma túy và rượu Các vấn đề tôn giáo, cả ủng hộ và phản biện - Nội dung khiêu dâm hardcore và softcore + Nội dung khiêu dâm nhẹ và mạnh bạo Trang phục khêu gợi và hình ảnh phụ nữ mặc quần áo hở hang - Quan điểm chính trị quan trọng + Quan điểm chính trị phê phán Các vấn đề về nhân quyền Thảo luận về các vấn đề môi trường Chủ nghĩa khủng bố, các phần tử bạo lực hoặc phong trào ly khai @@ -512,13 +512,13 @@ Các vấn đề sức khỏe tình dục bao gồm tránh thai, các bệnh lây qua đường tình dục, ngăn ngừa hiếp dâm và nạo phá thai Các vấn đề về y tế công cộng, như COVID-19, HIV/AIDS, Ebola Cờ bạc và cá độ trực truyến - Ẩn danh, vượt kiểm duyệt và mã hóa + Ẩn danh, vượt thoát kiểm duyệt và mã hóa Các trang hẹn hò trực tuyến Các nền tảng và công cụ mạng xã hội trực tuyến Cộng đồng LGBTQ + thảo luận về các vấn đề liên quan (trừ nội dung khiêu dâm) - Chia sẻ file bao gồm dữ liệu lưu trữ điện toán đám mây, torrent và P2P + Chia sẻ tập tin bao gồm dữ liệu lưu trữ điện toán đám mây, torrent và P2P Công cụ bảo mật máy tính và tin tức - Các công cụ giao tiếp cá nhân và nhóm bao gồm VoIP, nhắn tin và webmail + Công cụ giao tiếp cá nhân và nhóm bao gồm VoIP, nhắn tin và webmail Chia sẻ video, âm thanh và hình ảnh Lưu trữ web, viết blog và xuất bản trực tuyến khác Công cụ tìm kiếm và cổng thông tin