From e1207e7db6c7a2c24faeede0dc65bab7bf2d4590 Mon Sep 17 00:00:00 2001 From: Norbel AMBANUMBEN Date: Mon, 21 Oct 2024 10:09:59 +0100 Subject: [PATCH] OONI Run v2 (#671) * Next generation of OONI Run - OONI Run v2! * Updated UI of the cards displayed on the dashboard * Test settings for individual tests on each card * Changes to the "Run" button to allow users to enable/disable specific tests, including both OONI Probe tests and installed OONI Run links --------- Co-authored-by: Simone Basso --- app/build.gradle | 15 +- .../ui/MainActivityWebsitesTest.java | 117 ++-- .../ooniprobe/ui/RunningActivityTest.java | 10 +- .../ui/resultdetails/CircumventionTest.java | 23 +- .../resultdetails/InstantMessagingTest.java | 20 +- .../ui/resultdetails/PerformanceTest.java | 18 +- .../TestResultsMainScreenTest.java | 33 +- .../ui/resultdetails/WebsitesTest.java | 41 +- app/src/dw/assets/descriptors.json | 312 ++++++++++ .../RunTestsExpandableListViewAdapter.kt | 67 ++ .../ooniprobe/common/DefaultDescriptors.kt | 77 +++ app/src/dw/res/drawable/ooni_phone.xml | 4 + app/src/dw/res/layout/activity_prompt.xml | 85 +++ app/src/dw/res/layout/fragment_dashboard.xml | 207 +++--- app/src/dw/res/values-es/strings.xml | 2 +- app/src/dw/res/values-pt-rBR/strings.xml | 2 +- app/src/dw/res/values/dimens.xml | 1 + app/src/dw/res/values/untraslatable.xml | 6 + app/src/dw/res/xml/preferences_global.xml | 460 ++++++-------- app/src/dwDevFull/assets/descriptors.json | 122 ++++ app/src/fdroid/res/xml/preferences_global.xml | 481 ++++++-------- app/src/main/AndroidManifest.xml | 315 +++++----- app/src/main/assets/descriptors.json | 1 + .../ooniprobe/activity/AbstractActivity.java | 17 + .../activity/CustomWebsiteActivity.java | 124 ---- .../ooniprobe/activity/MainActivity.java | 241 ++++++- .../activity/MeasurementDetailActivity.java | 40 +- .../ooniprobe/activity/OoniRunActivity.java | 173 ----- .../ooniprobe/activity/OoniRunActivity.kt | 195 ++++++ .../ooniprobe/activity/OverviewActivity.java | 461 +++++++++++--- .../activity/ResultDetailActivity.kt | 93 ++- .../activity/ReviewUpdatesAbstractActivity.kt | 31 + .../ooniprobe/activity/RunningActivity.java | 31 +- .../adddescriptor/AddDescriptorActivity.kt | 225 +++++++ .../adddescriptor/AddDescriptorViewModel.kt | 114 ++++ .../AddDescriptorExpandableListAdapter.kt | 200 ++++++ .../customwebsites/CustomWebsiteActivity.kt | 173 +++++ .../customwebsites/CustomWebsiteViewModel.kt | 51 ++ .../CustomWebsiteRecyclerViewAdapter.kt | 91 +++ .../activity/oonirun/OoniRunV2Activity.kt | 188 ++++++ .../OverviewTestsExpandableListViewAdapter.kt | 179 ++++++ .../activity/overview/OverviewViewModel.kt | 170 +++++ .../activity/overview/RevisionsView.kt | 159 +++++ .../ReviewDescriptorUpdatesActivity.kt | 386 ++++++++++++ .../activity/runtests/RunTestsActivity.kt | 272 ++++++++ .../activity/runtests/RunTestsViewModel.kt | 35 ++ ...stractRunTestsExpandableListViewAdapter.kt | 307 +++++++++ .../activity/runtests/models/GroupItems.kt | 39 ++ .../ooniprobe/adapters/DashboardAdapter.kt | 61 +- .../ResultDetailExpandableListAdapter.kt | 16 +- .../adapters/StringListRecyclerViewAdapter.kt | 59 ++ .../ooniprobe/common/AppDatabase.java | 21 +- .../ooniprobe/common/AppUpdatesViewModel.kt | 26 + .../ooniprobe/common/Application.java | 8 +- .../ooniprobe/common/LocaleUtils.java | 5 +- .../ooniprobe/common/OONIDescriptor.kt | 367 +++++++++++ .../ooniprobe/common/PreferenceManager.java | 23 +- .../common/PreferenceManagerExtension.kt | 187 ++++++ .../ooniprobe/common/ReadMorePlugin.kt | 144 +++++ .../ooniprobe/common/StringUtils.java | 28 + .../ooniprobe/common/TaskExecutor.kt | 96 +++ .../ooniprobe/common/TestDescriptorManager.kt | 219 +++++++ .../ooniprobe/common/TestStateRepository.kt | 19 + .../common/service/RunTestService.java | 156 +++-- .../ooniprobe/common/service/ServiceUtil.java | 55 +- .../common/views/CustomExpandableListView.kt | 21 + .../common/worker/UpdateDescriptorsWorker.kt | 195 ++++++ .../ooniprobe/di/ActivityComponent.java | 12 +- .../ooniprobe/di/ServiceComponent.java | 2 + .../domain/GenerateAutoRunServiceSuite.java | 25 +- .../ooniprobe/domain/GetResults.java | 20 +- .../ooniprobe/domain/GetTestSuite.java | 61 +- .../ooniprobe/domain/MeasurementsManager.java | 2 +- .../domain/UpdatesNotificationManager.java | 1 + .../fragment/ConfirmDialogFragment.kt | 148 +++++ .../ooniprobe/fragment/DashboardFragment.kt | 125 +++- .../fragment/PreferenceFragment.java | 36 +- .../ooniprobe/fragment/ProgressFragment.java | 164 ----- .../ooniprobe/fragment/ProgressFragment.kt | 220 +++++++ .../fragment/ResultListFragment.java | 88 ++- .../fragment/dashboard/DashboardViewModel.kt | 88 ++- .../OONIRunDynamicProgressBar.kt | 119 ++++ .../fragment/measurement/FailedFragment.java | 33 +- .../onboarding/Onboarding2Fragment.java | 2 +- .../fragment/resultList/ResultListAdapter.kt | 35 ++ .../ooniprobe/item/FailedItem.java | 19 +- .../openobservatory/ooniprobe/item/RunItem.kt | 23 + .../ooniprobe/item/WebsiteItem.java | 15 + .../ooniprobe/model/database/Result.java | 412 ++++++------ .../model/database/TestDescriptor.kt | 294 +++++++++ .../ooniprobe/model/settings/Settings.java | 6 + .../receiver/TestRunBroadRequestReceiver.java | 17 +- .../ooniprobe/test/TestAsyncTask.java | 12 - .../ooniprobe/test/suite/AbstractSuite.java | 275 ++++---- .../test/suite/AbstractSuiteExtensions.kt | 35 ++ .../test/suite/CircumventionSuite.java | 54 -- .../ooniprobe/test/suite/DynamicTestSuite.kt | 83 +++ .../test/suite/ExperimentalSuite.java | 59 -- .../test/suite/InstantMessagingSuite.java | 58 -- .../test/suite/MiddleBoxesSuite.java | 53 -- .../test/suite/PerformanceSuite.java | 59 -- .../ooniprobe/test/suite/README.md | 17 + .../ooniprobe/test/suite/WebsitesSuite.java | 36 -- .../ooniprobe/test/test/AbstractTest.java | 72 ++- .../res/drawable-xxxhdpi/ic_menu_share.png | Bin 7247 -> 0 bytes .../main/res/drawable/add_circle_outline.xml | 5 + .../main/res/drawable/bottom_nav_color.xml | 5 + app/src/main/res/drawable/card_boarder.xml | 8 + app/src/main/res/drawable/check_box.xml | 5 + .../res/drawable/check_box_custom_button.xml | 8 + .../res/drawable/check_box_indeterminate.xml | 10 + .../res/drawable/check_box_outline_blank.xml | 5 + app/src/main/res/drawable/expand_less.xml | 5 + app/src/main/res/drawable/expand_more.xml | 5 + app/src/main/res/drawable/expired.xml | 11 + app/src/main/res/drawable/fa_anchor.xml | 9 + app/src/main/res/drawable/fa_award.xml | 9 + app/src/main/res/drawable/fa_bed.xml | 9 + app/src/main/res/drawable/fa_bolt.xml | 9 + app/src/main/res/drawable/fa_bone.xml | 9 + .../main/res/drawable/fa_book_open_reader.xml | 9 + app/src/main/res/drawable/fa_brush.xml | 9 + app/src/main/res/drawable/fa_building.xml | 9 + app/src/main/res/drawable/fa_cake_candles.xml | 9 + app/src/main/res/drawable/fa_car.xml | 9 + app/src/main/res/drawable/fa_carrot.xml | 9 + app/src/main/res/drawable/fa_cloud_rain.xml | 9 + app/src/main/res/drawable/fa_cloud_sun.xml | 9 + .../main/res/drawable/fa_cloud_sun_rain.xml | 9 + app/src/main/res/drawable/fa_compass.xml | 9 + app/src/main/res/drawable/fa_computer.xml | 9 + app/src/main/res/drawable/fa_crown.xml | 9 + app/src/main/res/drawable/fa_cube.xml | 9 + app/src/main/res/drawable/fa_dove.xml | 9 + app/src/main/res/drawable/fa_droplet.xml | 9 + .../main/res/drawable/fa_earth_americas.xml | 9 + app/src/main/res/drawable/fa_face_smile.xml | 9 + app/src/main/res/drawable/fa_faucet.xml | 9 + app/src/main/res/drawable/fa_film.xml | 9 + app/src/main/res/drawable/fa_fire.xml | 9 + app/src/main/res/drawable/fa_fish.xml | 9 + .../main/res/drawable/fa_flag_checkered.xml | 9 + app/src/main/res/drawable/fa_gauge.xml | 9 + app/src/main/res/drawable/fa_ghost.xml | 9 + app/src/main/res/drawable/fa_gift.xml | 9 + app/src/main/res/drawable/fa_glasses.xml | 9 + .../main/res/drawable/fa_graduation_cap.xml | 9 + app/src/main/res/drawable/fa_guitar.xml | 9 + app/src/main/res/drawable/fa_hammer.xml | 9 + app/src/main/res/drawable/fa_hand.xml | 9 + app/src/main/res/drawable/fa_handshake.xml | 9 + app/src/main/res/drawable/fa_heart.xml | 9 + app/src/main/res/drawable/fa_ice_cream.xml | 9 + app/src/main/res/drawable/fa_industry.xml | 9 + app/src/main/res/drawable/fa_magnet.xml | 9 + app/src/main/res/drawable/fa_map.xml | 9 + app/src/main/res/drawable/fa_meteor.xml | 9 + app/src/main/res/drawable/fa_microphone.xml | 9 + app/src/main/res/drawable/fa_microscope.xml | 9 + app/src/main/res/drawable/fa_money_bill.xml | 9 + app/src/main/res/drawable/fa_moon.xml | 9 + app/src/main/res/drawable/fa_mountain_sun.xml | 9 + app/src/main/res/drawable/fa_mug_hot.xml | 9 + app/src/main/res/drawable/fa_music.xml | 9 + app/src/main/res/drawable/fa_paw.xml | 9 + app/src/main/res/drawable/fa_pen_nib.xml | 9 + app/src/main/res/drawable/fa_pepper_hot.xml | 9 + .../main/res/drawable/fa_person_biking.xml | 9 + app/src/main/res/drawable/fa_pills.xml | 9 + app/src/main/res/drawable/fa_plane.xml | 9 + app/src/main/res/drawable/fa_plug.xml | 9 + app/src/main/res/drawable/fa_poo.xml | 9 + app/src/main/res/drawable/fa_radiation.xml | 9 + app/src/main/res/drawable/fa_radio.xml | 9 + app/src/main/res/drawable/fa_rainbow.xml | 9 + app/src/main/res/drawable/fa_ribbon.xml | 9 + app/src/main/res/drawable/fa_road.xml | 9 + app/src/main/res/drawable/fa_rocket.xml | 9 + app/src/main/res/drawable/fa_sack_dollar.xml | 9 + app/src/main/res/drawable/fa_scissors.xml | 9 + app/src/main/res/drawable/fa_seedling.xml | 9 + app/src/main/res/drawable/fa_shield.xml | 9 + app/src/main/res/drawable/fa_signs_post.xml | 9 + app/src/main/res/drawable/fa_skull.xml | 9 + app/src/main/res/drawable/fa_snowflake.xml | 9 + app/src/main/res/drawable/fa_socks.xml | 9 + app/src/main/res/drawable/fa_spider.xml | 9 + .../main/res/drawable/fa_suitcase_medical.xml | 9 + app/src/main/res/drawable/fa_sun.xml | 9 + .../fa_temperature_three_quarters.xml | 9 + app/src/main/res/drawable/fa_toilet_paper.xml | 9 + app/src/main/res/drawable/fa_tractor.xml | 9 + app/src/main/res/drawable/fa_tree.xml | 9 + app/src/main/res/drawable/fa_trophy.xml | 9 + app/src/main/res/drawable/fa_umbrella.xml | 9 + app/src/main/res/drawable/fa_utensils.xml | 9 + app/src/main/res/drawable/fa_wine_glass.xml | 9 + .../drawable/ic_baseline_remove_circle_24.xml | 9 - app/src/main/res/drawable/ic_menu_share.xml | 5 + app/src/main/res/drawable/ooni_phone.xml | 141 +++++ app/src/main/res/drawable/outline_timer.xml | 5 + app/src/main/res/drawable/progress_blue.xml | 2 +- app/src/main/res/drawable/warning_amber.xml | 9 + .../res/layout/activity_add_descriptor.xml | 205 ++++++ .../res/layout/activity_customwebsite.xml | 129 ++-- app/src/main/res/layout/activity_main.xml | 14 +- .../layout/activity_measurement_detail.xml | 8 - .../main/res/layout/activity_ooni_run_v2.xml | 58 ++ app/src/main/res/layout/activity_oonirun.xml | 147 ++--- app/src/main/res/layout/activity_overview.xml | 407 ++++++++---- .../res/layout/activity_result_detail.xml | 132 ++-- .../activity_review_descriptor_updates.xml | 61 ++ .../main/res/layout/activity_run_tests.xml | 116 ++++ app/src/main/res/layout/activity_running.xml | 4 +- app/src/main/res/layout/edittext_url.xml | 19 +- app/src/main/res/layout/expired_tag.xml | 29 + app/src/main/res/layout/fragment_content.xml | 36 +- .../main/res/layout/fragment_dashboard.xml | 268 ++++---- .../res/layout/fragment_descriptor_update.xml | 83 +++ app/src/main/res/layout/fragment_progress.xml | 100 +-- .../main/res/layout/fragment_result_list.xml | 1 - .../main/res/layout/fragment_revisions.xml | 35 ++ app/src/main/res/layout/item_experimental.xml | 1 + app/src/main/res/layout/item_run_v1.xml | 11 + app/src/main/res/layout/item_seperator.xml | 5 +- app/src/main/res/layout/item_testsuite.xml | 93 ++- app/src/main/res/layout/item_websites.xml | 3 +- .../res/layout/nettest_child_list_item.xml | 9 + .../res/layout/nettest_group_list_item.xml | 44 ++ .../layout/overview_test_child_list_item.xml | 10 + .../layout/overview_test_group_list_item.xml | 51 ++ .../res/layout/run_dynamic_progress_bar.xml | 49 ++ .../res/layout/run_tests_child_list_item.xml | 27 + .../res/layout/run_tests_group_divider.xml | 31 + .../res/layout/run_tests_group_list_item.xml | 50 ++ app/src/main/res/layout/updated_tag.xml | 30 + app/src/main/res/menu/close.xml | 10 + app/src/main/res/menu/share.xml | 4 +- .../menu/{run.xml => update_descriptor.xml} | 4 +- app/src/main/res/values-night/colors.xml | 9 +- app/src/main/res/values/colors.xml | 9 +- app/src/main/res/values/dimens.xml | 5 + app/src/main/res/values/strings.xml | 51 ++ app/src/main/res/values/styles.xml | 23 +- app/src/main/res/values/untraslatable.xml | 2 + app/src/main/res/xml/preferences_global.xml | 485 ++++++-------- app/src/ooni/AndroidManifest.xml | 96 +++ .../RunTestsExpandableListViewAdapter.kt | 15 + .../ooniprobe/common/DefaultDescriptors.kt | 129 ++++ app/src/ooni/res/values-ar/strings.xml | 51 ++ app/src/ooni/res/values-ca/strings.xml | 51 ++ app/src/ooni/res/values-de/strings.xml | 51 ++ app/src/ooni/res/values-el/strings.xml | 51 ++ app/src/ooni/res/values-es/strings.xml | 51 ++ app/src/ooni/res/values-fa/strings.xml | 51 ++ app/src/ooni/res/values-fr/strings.xml | 51 ++ app/src/ooni/res/values-hi/strings.xml | 51 ++ app/src/ooni/res/values-id/strings.xml | 589 ++++++++++-------- app/src/ooni/res/values-is/strings.xml | 51 ++ app/src/ooni/res/values-it/strings.xml | 51 ++ app/src/ooni/res/values-km/strings.xml | 584 +++++++++++++++++ app/src/ooni/res/values-my/strings.xml | 51 ++ app/src/ooni/res/values-nl/strings.xml | 51 ++ app/src/ooni/res/values-pt-rBR/strings.xml | 51 ++ app/src/ooni/res/values-ro/strings.xml | 51 ++ app/src/ooni/res/values-ru/strings.xml | 51 ++ app/src/ooni/res/values-sk/strings.xml | 51 ++ app/src/ooni/res/values-sq/strings.xml | 51 ++ app/src/ooni/res/values-sw/strings.xml | 55 +- app/src/ooni/res/values-th/strings.xml | 51 ++ app/src/ooni/res/values-tr/strings.xml | 51 ++ app/src/ooni/res/values-vi/strings.xml | 51 ++ app/src/ooni/res/values-zh-rCN/strings.xml | 51 ++ app/src/ooni/res/values-zh-rTW/strings.xml | 51 ++ app/src/ooni/res/values/untraslatable.xml | 2 + .../ooniprobe/common/ResubmitTaskTest.java | 11 +- .../ooniprobe/domain/GetResultsTest.java | 51 +- .../ooniprobe/domain/GetTestSuiteTest.java | 8 +- .../domain/MeasurementsManagerTest.java | 16 +- .../ooniprobe/model/database/NetworkTest.java | 4 +- .../ooniprobe/model/database/ResultTest.java | 46 +- .../ooniprobe/test/TestAsyncTaskTest.java | 17 +- .../test/suite/AbstractSuiteTest.java | 33 +- .../test/suite/CircumventionSuiteTest.java | 10 +- .../test/suite/ExperimentalSuiteTest.java | 30 +- .../test/suite/InstantMessagingSuiteTest.java | 9 +- .../test/suite/MiddleBoxesSuiteTest.java | 47 -- .../test/suite/PerformanceSuiteTest.java | 8 +- .../ooniprobe/test/test/AbstractTestTest.java | 20 +- engine/build.gradle | 6 +- .../org/openobservatory/engine/BaseNettest.kt | 13 + .../engine/OONIRunDescriptor.kt | 76 +++ .../openobservatory/engine/OONISession.java | 16 + .../org/openobservatory/engine/PESession.java | 33 + gradle/libs.versions.toml | 6 +- gradle/wrapper/gradle-wrapper.properties | 1 + run-v2-icons.md | 86 +++ .../ooniprobe/factory/ResultFactory.java | 46 +- 298 files changed, 14059 insertions(+), 3870 deletions(-) create mode 100644 app/src/dw/assets/descriptors.json create mode 100644 app/src/dw/kotlin/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt create mode 100644 app/src/dw/kotlin/org/openobservatory/ooniprobe/common/DefaultDescriptors.kt create mode 100644 app/src/dw/res/drawable/ooni_phone.xml create mode 100644 app/src/dw/res/layout/activity_prompt.xml create mode 100644 app/src/dwDevFull/assets/descriptors.json create mode 100644 app/src/main/assets/descriptors.json delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/CustomWebsiteActivity.java delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/OoniRunActivity.java create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/OoniRunActivity.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/ReviewUpdatesAbstractActivity.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorActivity.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorViewModel.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/adapter/AddDescriptorExpandableListAdapter.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/customwebsites/CustomWebsiteActivity.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/customwebsites/CustomWebsiteViewModel.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/customwebsites/adapter/CustomWebsiteRecyclerViewAdapter.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/oonirun/OoniRunV2Activity.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/overview/OverviewTestsExpandableListViewAdapter.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/overview/OverviewViewModel.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/overview/RevisionsView.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/reviewdescriptorupdates/ReviewDescriptorUpdatesActivity.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/runtests/RunTestsActivity.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/runtests/RunTestsViewModel.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/runtests/adapter/AbstractRunTestsExpandableListViewAdapter.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/activity/runtests/models/GroupItems.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/adapters/StringListRecyclerViewAdapter.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/AppUpdatesViewModel.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/OONIDescriptor.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/PreferenceManagerExtension.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/ReadMorePlugin.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/StringUtils.java create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/TaskExecutor.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/TestDescriptorManager.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/TestStateRepository.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/views/CustomExpandableListView.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/common/worker/UpdateDescriptorsWorker.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/fragment/ConfirmDialogFragment.kt delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/fragment/ProgressFragment.java create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/fragment/ProgressFragment.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/fragment/dynamicprogressbar/OONIRunDynamicProgressBar.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/fragment/resultList/ResultListAdapter.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/item/RunItem.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/model/database/TestDescriptor.kt create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/AbstractSuiteExtensions.kt delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/CircumventionSuite.java create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/DynamicTestSuite.kt delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/ExperimentalSuite.java delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/InstantMessagingSuite.java delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/MiddleBoxesSuite.java delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/PerformanceSuite.java create mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/README.md delete mode 100644 app/src/main/java/org/openobservatory/ooniprobe/test/suite/WebsitesSuite.java delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_menu_share.png create mode 100644 app/src/main/res/drawable/add_circle_outline.xml create mode 100644 app/src/main/res/drawable/bottom_nav_color.xml create mode 100644 app/src/main/res/drawable/card_boarder.xml create mode 100644 app/src/main/res/drawable/check_box.xml create mode 100644 app/src/main/res/drawable/check_box_custom_button.xml create mode 100644 app/src/main/res/drawable/check_box_indeterminate.xml create mode 100644 app/src/main/res/drawable/check_box_outline_blank.xml create mode 100644 app/src/main/res/drawable/expand_less.xml create mode 100644 app/src/main/res/drawable/expand_more.xml create mode 100644 app/src/main/res/drawable/expired.xml create mode 100644 app/src/main/res/drawable/fa_anchor.xml create mode 100644 app/src/main/res/drawable/fa_award.xml create mode 100644 app/src/main/res/drawable/fa_bed.xml create mode 100644 app/src/main/res/drawable/fa_bolt.xml create mode 100644 app/src/main/res/drawable/fa_bone.xml create mode 100644 app/src/main/res/drawable/fa_book_open_reader.xml create mode 100644 app/src/main/res/drawable/fa_brush.xml create mode 100644 app/src/main/res/drawable/fa_building.xml create mode 100644 app/src/main/res/drawable/fa_cake_candles.xml create mode 100644 app/src/main/res/drawable/fa_car.xml create mode 100644 app/src/main/res/drawable/fa_carrot.xml create mode 100644 app/src/main/res/drawable/fa_cloud_rain.xml create mode 100644 app/src/main/res/drawable/fa_cloud_sun.xml create mode 100644 app/src/main/res/drawable/fa_cloud_sun_rain.xml create mode 100644 app/src/main/res/drawable/fa_compass.xml create mode 100644 app/src/main/res/drawable/fa_computer.xml create mode 100644 app/src/main/res/drawable/fa_crown.xml create mode 100644 app/src/main/res/drawable/fa_cube.xml create mode 100644 app/src/main/res/drawable/fa_dove.xml create mode 100644 app/src/main/res/drawable/fa_droplet.xml create mode 100644 app/src/main/res/drawable/fa_earth_americas.xml create mode 100644 app/src/main/res/drawable/fa_face_smile.xml create mode 100644 app/src/main/res/drawable/fa_faucet.xml create mode 100644 app/src/main/res/drawable/fa_film.xml create mode 100644 app/src/main/res/drawable/fa_fire.xml create mode 100644 app/src/main/res/drawable/fa_fish.xml create mode 100644 app/src/main/res/drawable/fa_flag_checkered.xml create mode 100644 app/src/main/res/drawable/fa_gauge.xml create mode 100644 app/src/main/res/drawable/fa_ghost.xml create mode 100644 app/src/main/res/drawable/fa_gift.xml create mode 100644 app/src/main/res/drawable/fa_glasses.xml create mode 100644 app/src/main/res/drawable/fa_graduation_cap.xml create mode 100644 app/src/main/res/drawable/fa_guitar.xml create mode 100644 app/src/main/res/drawable/fa_hammer.xml create mode 100644 app/src/main/res/drawable/fa_hand.xml create mode 100644 app/src/main/res/drawable/fa_handshake.xml create mode 100644 app/src/main/res/drawable/fa_heart.xml create mode 100644 app/src/main/res/drawable/fa_ice_cream.xml create mode 100644 app/src/main/res/drawable/fa_industry.xml create mode 100644 app/src/main/res/drawable/fa_magnet.xml create mode 100644 app/src/main/res/drawable/fa_map.xml create mode 100644 app/src/main/res/drawable/fa_meteor.xml create mode 100644 app/src/main/res/drawable/fa_microphone.xml create mode 100644 app/src/main/res/drawable/fa_microscope.xml create mode 100644 app/src/main/res/drawable/fa_money_bill.xml create mode 100644 app/src/main/res/drawable/fa_moon.xml create mode 100644 app/src/main/res/drawable/fa_mountain_sun.xml create mode 100644 app/src/main/res/drawable/fa_mug_hot.xml create mode 100644 app/src/main/res/drawable/fa_music.xml create mode 100644 app/src/main/res/drawable/fa_paw.xml create mode 100644 app/src/main/res/drawable/fa_pen_nib.xml create mode 100644 app/src/main/res/drawable/fa_pepper_hot.xml create mode 100644 app/src/main/res/drawable/fa_person_biking.xml create mode 100644 app/src/main/res/drawable/fa_pills.xml create mode 100644 app/src/main/res/drawable/fa_plane.xml create mode 100644 app/src/main/res/drawable/fa_plug.xml create mode 100644 app/src/main/res/drawable/fa_poo.xml create mode 100644 app/src/main/res/drawable/fa_radiation.xml create mode 100644 app/src/main/res/drawable/fa_radio.xml create mode 100644 app/src/main/res/drawable/fa_rainbow.xml create mode 100644 app/src/main/res/drawable/fa_ribbon.xml create mode 100644 app/src/main/res/drawable/fa_road.xml create mode 100644 app/src/main/res/drawable/fa_rocket.xml create mode 100644 app/src/main/res/drawable/fa_sack_dollar.xml create mode 100644 app/src/main/res/drawable/fa_scissors.xml create mode 100644 app/src/main/res/drawable/fa_seedling.xml create mode 100644 app/src/main/res/drawable/fa_shield.xml create mode 100644 app/src/main/res/drawable/fa_signs_post.xml create mode 100644 app/src/main/res/drawable/fa_skull.xml create mode 100644 app/src/main/res/drawable/fa_snowflake.xml create mode 100644 app/src/main/res/drawable/fa_socks.xml create mode 100644 app/src/main/res/drawable/fa_spider.xml create mode 100644 app/src/main/res/drawable/fa_suitcase_medical.xml create mode 100644 app/src/main/res/drawable/fa_sun.xml create mode 100644 app/src/main/res/drawable/fa_temperature_three_quarters.xml create mode 100644 app/src/main/res/drawable/fa_toilet_paper.xml create mode 100644 app/src/main/res/drawable/fa_tractor.xml create mode 100644 app/src/main/res/drawable/fa_tree.xml create mode 100644 app/src/main/res/drawable/fa_trophy.xml create mode 100644 app/src/main/res/drawable/fa_umbrella.xml create mode 100644 app/src/main/res/drawable/fa_utensils.xml create mode 100644 app/src/main/res/drawable/fa_wine_glass.xml delete mode 100644 app/src/main/res/drawable/ic_baseline_remove_circle_24.xml create mode 100644 app/src/main/res/drawable/ic_menu_share.xml create mode 100644 app/src/main/res/drawable/ooni_phone.xml create mode 100644 app/src/main/res/drawable/outline_timer.xml create mode 100644 app/src/main/res/drawable/warning_amber.xml create mode 100644 app/src/main/res/layout/activity_add_descriptor.xml create mode 100644 app/src/main/res/layout/activity_ooni_run_v2.xml create mode 100644 app/src/main/res/layout/activity_review_descriptor_updates.xml create mode 100644 app/src/main/res/layout/activity_run_tests.xml create mode 100644 app/src/main/res/layout/expired_tag.xml create mode 100644 app/src/main/res/layout/fragment_descriptor_update.xml create mode 100644 app/src/main/res/layout/fragment_revisions.xml create mode 100644 app/src/main/res/layout/item_run_v1.xml create mode 100644 app/src/main/res/layout/nettest_child_list_item.xml create mode 100644 app/src/main/res/layout/nettest_group_list_item.xml create mode 100644 app/src/main/res/layout/overview_test_child_list_item.xml create mode 100644 app/src/main/res/layout/overview_test_group_list_item.xml create mode 100644 app/src/main/res/layout/run_dynamic_progress_bar.xml create mode 100644 app/src/main/res/layout/run_tests_child_list_item.xml create mode 100644 app/src/main/res/layout/run_tests_group_divider.xml create mode 100644 app/src/main/res/layout/run_tests_group_list_item.xml create mode 100644 app/src/main/res/layout/updated_tag.xml create mode 100644 app/src/main/res/menu/close.xml rename app/src/main/res/menu/{run.xml => update_descriptor.xml} (68%) create mode 100644 app/src/ooni/AndroidManifest.xml create mode 100644 app/src/ooni/kotlin/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt create mode 100644 app/src/ooni/kotlin/org/openobservatory/ooniprobe/common/DefaultDescriptors.kt create mode 100644 app/src/ooni/res/values-km/strings.xml delete mode 100644 app/src/test/java/org/openobservatory/ooniprobe/test/suite/MiddleBoxesSuiteTest.java create mode 100644 engine/src/main/java/org/openobservatory/engine/BaseNettest.kt create mode 100644 engine/src/main/java/org/openobservatory/engine/OONIRunDescriptor.kt create mode 100644 run-v2-icons.md diff --git a/app/build.gradle b/app/build.gradle index c8e5f2c0b..63a9e3fe6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,13 +13,15 @@ android { applicationId 'org.openobservatory.ooniprobe' minSdk libs.versions.minSdk.get().toInteger() targetSdk libs.versions.targetSdk.get().toInteger() - versionName '3.9.0-beta' - versionCode 119 + versionName '4.0.0' + versionCode 122 testInstrumentationRunner "org.openobservatory.ooniprobe.TestAndroidJUnitRunner" - buildConfigField 'String', 'OONI_API_BASE_URL', '"https://api.ooni.io/"' + buildConfigField 'String', 'OONI_API_BASE_URL', '"https://api.ooni.org"' buildConfigField 'String', 'NOTIFICATION_SERVER', '"https://countly.ooni.io"' + buildConfigField 'String', 'OONI_RUN_DASHBOARD_URL', '"https://run.ooni.org"' resValue "string", "APP_ID", 'org.openobservatory.ooniprobe' resValue "string", "APP_NAME", "OONI Probe" + resValue "string", "RUN_V2_DOMAIN", "run.ooni.org" buildConfigField 'String', 'SOFTWARE_NAME', 'BASE_SOFTWARE_NAME+IS_DEBUG' buildConfigField 'String', 'COUNTLY_KEY', '"146836f41172f9e3287cab6f2cc347de3f5ddf3b"' buildConfigField "boolean", "RUN_AUTOMATION", "false" @@ -120,6 +122,10 @@ android { viewBinding = true buildConfig = true } + dataBinding { + enabled = true + enabledForTests = true + } namespace 'org.openobservatory.ooniprobe' } @@ -136,6 +142,7 @@ dependencies { implementation libs.androidx.preference implementation libs.androidx.localbroadcastmanager implementation libs.androidx.legacy.support.v4 + implementation libs.androidx.work.runtime // Google implementation libs.google.material @@ -177,7 +184,7 @@ dependencies { // Unit Testing testImplementation project(':shared-test') testImplementation libs.junit4 - testImplementation libs.androidx.core + testImplementation libs.androidx.test.core testImplementation libs.androidx.runner testImplementation libs.androidx.rules testImplementation libs.mockito.core diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/MainActivityWebsitesTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/MainActivityWebsitesTest.java index 1e7eb3d9b..3aea016cf 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/MainActivityWebsitesTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/MainActivityWebsitesTest.java @@ -1,47 +1,44 @@ package org.openobservatory.ooniprobe.ui; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.action.ViewActions.typeText; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; +import static androidx.test.espresso.intent.Intents.intending; +import static androidx.test.espresso.intent.matcher.IntentMatchers.anyIntent; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static org.openobservatory.ooniprobe.ui.utils.RecyclerViewMatcher.withRecyclerView; +import static org.openobservatory.ooniprobe.ui.utils.ViewMatchers.withIndex; + import android.app.Activity; import android.app.Instrumentation; import android.content.Intent; +import android.view.View; import androidx.test.core.app.ActivityScenario; import androidx.test.core.app.ApplicationProvider; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.contrib.RecyclerViewActions; import androidx.test.espresso.intent.Intents; -import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.adevinta.android.barista.rule.flaky.AllowFlaky; import com.adevinta.android.barista.rule.flaky.FlakyTestRule; +import org.hamcrest.Matcher; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.AbstractTest; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.activity.MainActivity; -import org.openobservatory.ooniprobe.activity.RunningActivity; -import org.openobservatory.ooniprobe.fragment.ProgressFragment; import io.bloco.faker.Faker; -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.action.ViewActions.typeText; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; -import static androidx.test.espresso.intent.Intents.intended; -import static androidx.test.espresso.intent.Intents.intending; -import static androidx.test.espresso.intent.matcher.ComponentNameMatchers.hasClassName; -import static androidx.test.espresso.intent.matcher.IntentMatchers.anyIntent; -import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.not; -import static org.openobservatory.ooniprobe.ui.utils.RecyclerViewMatcher.withRecyclerView; -import static org.openobservatory.ooniprobe.ui.utils.ViewMatchers.withIndex; - @RunWith(AndroidJUnit4.class) public class MainActivityWebsitesTest extends AbstractTest { @@ -50,6 +47,26 @@ public class MainActivityWebsitesTest extends AbstractTest { @Rule public FlakyTestRule flakyRule = new FlakyTestRule(); + public static ViewAction clickChildViewWithId(final int id) { + return new ViewAction() { + @Override + public Matcher getConstraints() { + return null; + } + + @Override + public String getDescription() { + return "Click on a child view with specified id."; + } + + @Override + public void perform(UiController uiController, View view) { + View v = view.findViewById(id); + v.performClick(); + } + }; + } + @Test @AllowFlaky(attempts = 3) public void addCustomWebsiteTest() { @@ -62,22 +79,17 @@ public void addCustomWebsiteTest() { // Act launchDashboard(); - onView(withId(R.id.recycler)) - .perform(scrollToPosition(0)); + onView(withId(R.id.recycler)).perform(scrollToPosition(1)); - onView(withRecyclerView(R.id.recycler) - .atPositionOnView(0, R.id.title)) - .perform(click()); + onView(withRecyclerView(R.id.recycler).atPositionOnView(1, R.id.title)).perform(click()); onView(withId(R.id.customUrl)).perform(click()); - onView(withIndex(withId(R.id.editText), 0)) - .perform(typeText(url1)); + onView(withIndex(withId(R.id.editText), 0)).perform(typeText(url1)); onView(withId(R.id.add)).perform(click()); - onView(withIndex(withId(R.id.editText), 1)) - .perform(typeText(url2)); + onView(withIndex(withId(R.id.editText), 1)).perform(typeText(url2)); // Assert onView(withText(totalUrls)).check(matches(isDisplayed())); @@ -90,32 +102,32 @@ public void deleteCustomWebsiteTest() { Faker faker = new Faker(); String url1 = faker.internet.domainName() + faker.internet.domainSuffix(); String url2 = faker.internet.domainName() + faker.internet.domainSuffix(); - String totalUrls = String.format(getResourceString(R.string.OONIRun_URLs), 1); + String totalUrls = String.format("Test %s URLs", 1); // Act launchDashboard(); - onView(withId(R.id.recycler)) - .perform(scrollToPosition(0)); + onView(withId(R.id.recycler)).perform(scrollToPosition(1)); - onView(withRecyclerView(R.id.recycler) - .atPositionOnView(0, R.id.title)) - .perform(click()); + onView(withRecyclerView(R.id.recycler).atPositionOnView(1, R.id.title)).perform(click()); onView(withId(R.id.customUrl)).perform(click()); - onView(withIndex(withId(R.id.editText), 0)) - .perform(typeText(url1)); + onView(withIndex(withId(R.id.editText), 0)).perform(typeText(url1)); + + onView(withId(R.id.urlContainer)).perform(scrollToPosition(0)); - onView(withIndex(withId(R.id.delete), 0)) - .check(matches(not(isDisplayed()))); + onView(withRecyclerView(R.id.urlContainer).atPositionOnView(0, R.id.delete)).check(matches(isDisplayed())); onView(withId(R.id.add)).perform(click()); - onView(withIndex(withId(R.id.editText), 1)) - .perform(typeText(url2)); + onView(withIndex(withId(R.id.editText), 1)).perform(typeText(url2)); - onView(withIndex(withId(R.id.delete), 1)) - .perform(click()); + onView(withIndex(withId(R.id.delete), 1)).perform(click()); + + onView(withId(R.id.urlContainer)).perform(scrollToPosition(1)); + + // TODO: fix click action + onView(withRecyclerView(R.id.urlContainer).atPosition(1)).perform(RecyclerViewActions.actionOnItemAtPosition(1, clickChildViewWithId(R.id.delete))); // Assert onView(withText(totalUrls)).check(matches(isDisplayed())); @@ -126,29 +138,18 @@ public void deleteCustomWebsiteTest() { public void lunchCustomWebsiteIntentTest() { // Act launchDashboard(); - onView(withId(R.id.recycler)) - .perform(scrollToPosition(0)); + onView(withId(R.id.recycler)).perform(scrollToPosition(1)); - onView(withRecyclerView(R.id.recycler) - .atPositionOnView(0, R.id.title)) - .perform(click()); + onView(withRecyclerView(R.id.recycler).atPositionOnView(1, R.id.title)).perform(click()); onView(withId(R.id.customUrl)).perform(click()); Intents.init(); Intent emptyIntent = new Intent(); - Instrumentation.ActivityResult result = - new Instrumentation.ActivityResult(Activity.RESULT_OK, emptyIntent); + Instrumentation.ActivityResult result = new Instrumentation.ActivityResult(Activity.RESULT_OK, emptyIntent); intending(anyIntent()).respondWith(result); - - onView(withId(R.id.runButton)).perform(click()); - // TODO(aanorbel): resolve issue. Running activity no longer available. - // ```intended(hasComponent(hasClassName(RunningActivity.class.getName())));``` - // progress display is dismissed before its availability is checked - // ```onView(withId(R.id.progress_layout)).check(matches(isDisplayed()));``` - Intents.release(); } diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/RunningActivityTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/RunningActivityTest.java index 9bd23c078..b4bb217c7 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/RunningActivityTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/RunningActivityTest.java @@ -6,9 +6,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ServiceTestRule; -import com.adevinta.android.barista.rule.flaky.AllowFlaky; -import com.adevinta.android.barista.rule.flaky.FlakyTestRule; - import org.junit.After; import org.junit.Rule; import org.junit.Test; @@ -17,12 +14,12 @@ import org.openobservatory.ooniprobe.AbstractTest; import org.openobservatory.ooniprobe.activity.MainActivity; import org.openobservatory.ooniprobe.activity.RunningActivity; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.common.service.RunTestService; import org.openobservatory.ooniprobe.engine.TestEngineInterface; import org.openobservatory.ooniprobe.model.jsonresult.EventResult; import org.openobservatory.ooniprobe.test.EngineProvider; import org.openobservatory.ooniprobe.test.suite.AbstractSuite; -import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite; import org.openobservatory.ooniprobe.utils.DatabaseUtils; import java.util.ArrayList; @@ -31,6 +28,9 @@ import static org.openobservatory.ooniprobe.testing.ActivityAssertions.assertCurrentActivity; import static org.openobservatory.ooniprobe.testing.ActivityAssertions.waitForCurrentActivity; +import com.adevinta.android.barista.rule.flaky.AllowFlaky; +import com.adevinta.android.barista.rule.flaky.FlakyTestRule; + @RunWith(AndroidJUnit4.class) public class RunningActivityTest extends AbstractTest { @@ -87,7 +87,7 @@ private void startRunTestService() { serviceRule.startService( new Intent(c, RunTestService.class) .putExtra("testSuites", new ArrayList() {{ - add(new InstantMessagingSuite()); + add(OONITests.WEBSITES.toOONIDescriptor(c).getTest(c)); }}) ); } catch (TimeoutException e) { diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/CircumventionTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/CircumventionTest.java index 17bdb976a..ea5bbcae1 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/CircumventionTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/CircumventionTest.java @@ -1,26 +1,23 @@ package org.openobservatory.ooniprobe.ui.resultdetails; import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.adevinta.android.barista.rule.flaky.AllowFlaky; -import com.adevinta.android.barista.rule.flaky.FlakyTestRule; - import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Result; -import org.openobservatory.ooniprobe.test.suite.CircumventionSuite; import org.openobservatory.ooniprobe.utils.FormattingUtils; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.matcher.ViewMatchers.*; + +import com.adevinta.android.barista.rule.flaky.AllowFlaky; +import com.adevinta.android.barista.rule.flaky.FlakyTestRule; @RunWith(AndroidJUnit4.class) public class CircumventionTest extends MeasurementAbstractTest { @@ -32,7 +29,7 @@ public class CircumventionTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 3, 0); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 3, 0); // Act launchDetails(testResult.id); @@ -44,7 +41,7 @@ public void testHeaderData() { @Test public void testSuccessPsiphon() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 3, 0); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 3, 0); Measurement measurement = testResult.getMeasurement("psiphon"); String formattedBootstrap = FormattingUtils.formatBootstrap(measurement.getTestKeys().bootstrap_time); @@ -61,7 +58,7 @@ public void testSuccessPsiphon() { @Test public void testBlockedPsiphon() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 0, 3); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 0, 3); Measurement measurement = testResult.getMeasurement("psiphon"); // Act @@ -77,7 +74,7 @@ public void testBlockedPsiphon() { @Test public void testSuccessTor() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 3, 0); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 3, 0); Measurement measurement = testResult.getMeasurement("tor"); String formattedBridges = FormattingUtils.getFormattedBridges(measurement); @@ -97,7 +94,7 @@ public void testSuccessTor() { @Test public void testBlockedTor() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 0, 3); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 0, 3); Measurement measurement = testResult.getMeasurement("tor"); String formattedBridges = FormattingUtils.getFormattedBridges(measurement); diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/InstantMessagingTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/InstantMessagingTest.java index 45214d59a..35b8a086c 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/InstantMessagingTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/InstantMessagingTest.java @@ -9,9 +9,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Result; -import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; @@ -30,7 +30,7 @@ public class InstantMessagingTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -43,7 +43,7 @@ public void testHeaderData() { @AllowFlaky(attempts = 2) public void testSuccessWhatsApp() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -57,7 +57,7 @@ public void testSuccessWhatsApp() { @Test public void testBlockedWhatsApp() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite(), 0, 4); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c), 0, 4); // Act launchDetails(testResult.id); @@ -72,7 +72,7 @@ public void testBlockedWhatsApp() { @Test public void testSuccessTelegram() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -87,7 +87,7 @@ public void testSuccessTelegram() { @Test public void testBlockedTelegram() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite(), 0, 4); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c), 0, 4); // Act launchDetails(testResult.id); @@ -102,7 +102,7 @@ public void testBlockedTelegram() { @Test public void testSuccessFacebookMessenger() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -117,7 +117,7 @@ public void testSuccessFacebookMessenger() { @Test public void testBlockedFacebookMessenger() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite(), 0, 4); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c), 0, 4); // Act launchDetails(testResult.id); @@ -132,7 +132,7 @@ public void testBlockedFacebookMessenger() { @Test public void testSuccessSignal() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -146,7 +146,7 @@ public void testSuccessSignal() { @Test public void testBlockedSignal() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite(), 0, 4); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c), 0, 4); // Act launchDetails(testResult.id); diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/PerformanceTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/PerformanceTest.java index 867ba6199..7cfa4b67f 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/PerformanceTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/PerformanceTest.java @@ -22,11 +22,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Result; import org.openobservatory.ooniprobe.model.jsonresult.TestKeys; -import org.openobservatory.ooniprobe.test.suite.PerformanceSuite; import org.openobservatory.ooniprobe.test.test.Dash; import org.openobservatory.ooniprobe.test.test.HttpHeaderFieldManipulation; import org.openobservatory.ooniprobe.test.test.HttpInvalidRequestLine; @@ -43,7 +43,7 @@ public class PerformanceTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement dashMeasurement = testResult.getMeasurement(Dash.NAME); String videoQuality = getResourceString(dashMeasurement.getTestKeys().getVideoQuality(false)); @@ -90,7 +90,7 @@ public void testHeaderData() { @Test public void testListOfMeasurements() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement dashMeasurement = testResult.getMeasurement(Dash.NAME); String videoQuality = getResourceString(dashMeasurement.getTestKeys().getVideoQuality(true)); String notDetected = getResourceString(R.string.TestResults_Overview_MiddleBoxes_NotFound); @@ -146,7 +146,7 @@ public void testListOfMeasurements() { @Test public void testNDT() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement ndtMeasurement = testResult.getMeasurement(Ndt.NAME); Integer ndtProtocol = ndtMeasurement.getTestKeys().protocol; TestKeys.Summary ndtSummary = ndtMeasurement.getTestKeys().summary; @@ -192,7 +192,7 @@ public void testNDT() { @Test public void testStreaming() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement dashMeasurement = testResult.getMeasurement(Dash.NAME); String videoQuality = getResourceString(dashMeasurement.getTestKeys().getVideoQuality(true)); String bitrateUnit = getResourceString(dashMeasurement.getTestKeys().getMedianBitrateUnit()); @@ -213,7 +213,7 @@ public void testStreaming() { @Test public void testRequestLine() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement invalidRequest = testResult.getMeasurement(HttpInvalidRequestLine.NAME); // Act @@ -228,7 +228,7 @@ public void testRequestLine() { @Test public void testRequestLineDetection() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite(), 2, 2); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c), 2, 2); Measurement invalidRequest = testResult.getMeasurement(HttpInvalidRequestLine.NAME); // Act @@ -243,7 +243,7 @@ public void testRequestLineDetection() { @Test public void testFieldManipulation() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement fieldManipulation = testResult.getMeasurement(HttpHeaderFieldManipulation.NAME); // Act @@ -258,7 +258,7 @@ public void testFieldManipulation() { @Test public void testFieldManipulationDetection() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite(), 2, 2); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c), 2, 2); Measurement fieldManipulation = testResult.getMeasurement(HttpHeaderFieldManipulation.NAME); // Act diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/TestResultsMainScreenTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/TestResultsMainScreenTest.java index ccac85cc7..838113cee 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/TestResultsMainScreenTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/TestResultsMainScreenTest.java @@ -9,13 +9,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Result; import org.openobservatory.ooniprobe.model.jsonresult.TestKeys; -import org.openobservatory.ooniprobe.test.suite.CircumventionSuite; -import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite; -import org.openobservatory.ooniprobe.test.suite.PerformanceSuite; -import org.openobservatory.ooniprobe.test.suite.WebsitesSuite; import org.openobservatory.ooniprobe.test.test.Dash; import org.openobservatory.ooniprobe.test.test.Ndt; import org.openobservatory.ooniprobe.utils.FormattingUtils; @@ -49,10 +46,10 @@ public class TestResultsMainScreenTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result websites = ResultFactory.createAndSave(new WebsitesSuite()); - Result messaging = ResultFactory.createAndSave(new InstantMessagingSuite()); - Result circumvention = ResultFactory.createAndSave(new CircumventionSuite(), 1, 2); - Result performance = ResultFactory.createAndSave(new PerformanceSuite()); + Result websites = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); + Result messaging = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); + Result circumvention = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 1, 2); + Result performance = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); long totalDownload = websites.data_usage_down + messaging.data_usage_down + @@ -78,19 +75,19 @@ public void testHeaderData() { @AllowFlaky(attempts = 3) public void testListOfResults() { // Arrange - Result websites = ResultFactory.createAndSave(new WebsitesSuite()); + Result websites = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); websites.start_time = getDateFrom(1, Calendar.JANUARY, 2020); websites.save(); - Result messaging = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result messaging = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); messaging.start_time = getDateFrom(1, Calendar.FEBRUARY, 2020); messaging.save(); - Result circumvention = ResultFactory.createAndSave(new CircumventionSuite(), 1, 2); + Result circumvention = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 1, 2); circumvention.start_time = getDateFrom(1, Calendar.MARCH, 2020); circumvention.save(); - Result performance = ResultFactory.createAndSave(new PerformanceSuite()); + Result performance = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); performance.start_time = getDateFrom(1, Calendar.APRIL, 2020); performance.save(); @@ -189,8 +186,8 @@ public void testListOfResults() { @AllowFlaky(attempts = 3) public void deleteResultsTest() { // Arrange - ResultFactory.createAndSave(new WebsitesSuite()); - ResultFactory.createAndSave(new PerformanceSuite()); + ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); + ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); // Act launchResults(); @@ -208,19 +205,19 @@ public void deleteResultsTest() { @AllowFlaky(attempts = 3) public void filterTest() { // Arrange - Result websites = ResultFactory.createAndSave(new WebsitesSuite()); + Result websites = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); websites.start_time = getDateFrom(1, Calendar.JANUARY, 2020); websites.save(); - Result messaging = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result messaging = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); messaging.start_time = getDateFrom(1, Calendar.FEBRUARY, 2020); messaging.save(); - Result circumvention = ResultFactory.createAndSave(new CircumventionSuite(), 1, 2); + Result circumvention = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 1, 2); circumvention.start_time = getDateFrom(1, Calendar.MARCH, 2020); circumvention.save(); - Result performance = ResultFactory.createAndSave(new PerformanceSuite()); + Result performance = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); performance.start_time = getDateFrom(1, Calendar.APRIL, 2020); performance.save(); diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/WebsitesTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/WebsitesTest.java index 31752d31f..05a4268c7 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/WebsitesTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/WebsitesTest.java @@ -1,5 +1,19 @@ package org.openobservatory.ooniprobe.ui.resultdetails; +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.containsString; +import static org.openobservatory.ooniprobe.ui.utils.RecyclerViewMatcher.withRecyclerView; +import static org.openobservatory.ooniprobe.ui.utils.ViewMatchers.waitPartialText; + import androidx.test.ext.junit.runners.AndroidJUnit4; import com.adevinta.android.barista.rule.flaky.AllowFlaky; @@ -10,29 +24,14 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Result; -import org.openobservatory.ooniprobe.test.suite.WebsitesSuite; import java.util.List; import java.util.concurrent.TimeUnit; -import static androidx.test.espresso.Espresso.onData; -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; -import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.isRoot; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.anything; -import static org.hamcrest.Matchers.containsString; -import static org.openobservatory.ooniprobe.ui.utils.RecyclerViewMatcher.withRecyclerView; -import static org.openobservatory.ooniprobe.ui.utils.ViewMatchers.waitPartialText; - @RunWith(AndroidJUnit4.class) public class WebsitesTest extends MeasurementAbstractTest { @@ -43,7 +42,7 @@ public class WebsitesTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result testResult = ResultFactory.createAndSave(new WebsitesSuite(), 10, 2); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c), 10, 2); // Act launchDetails(testResult.id); @@ -58,7 +57,7 @@ public void checkListOfMeasurementsTest() { int successfulMeasurements = 10; int failedMeasurement = 2; - Result testResult = ResultFactory.createAndSave(new WebsitesSuite(), successfulMeasurements, failedMeasurement); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c), successfulMeasurements, failedMeasurement); List measurements = testResult.getMeasurementsSorted(); // Act @@ -78,7 +77,7 @@ public void checkListOfMeasurementsTest() { @Test public void testSucceed() { // Arrange - Result testResult = ResultFactory.createAndSave(new WebsitesSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); Measurement measurement = testResult.getMeasurementsSorted().get(0); String headerOutcome = measurement.getUrlString() + "\n" + getResourceString(R.string.TestResults_Details_Websites_Reachable_Hero_Title); @@ -94,7 +93,7 @@ public void testSucceed() { @Test public void testBlocked() { // Arrange - Result testResult = ResultFactory.createAndSave(new WebsitesSuite(), 0, 3); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c), 0, 3); Measurement measurement = testResult.getMeasurementsSorted().get(0); String headerOutcome = measurement.getUrlString() + "\n" + BLOCKED_OUTCOME; @@ -115,7 +114,7 @@ public void canRerunTest() { int failedMeasurement = 2; int totalNumberOfMeasurements = successfulMeasurements + failedMeasurement; - Result testResult = ResultFactory.createAndSave(new WebsitesSuite(), successfulMeasurements, failedMeasurement); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c), successfulMeasurements, failedMeasurement); String websites = totalNumberOfMeasurements + " " + getResourceString(R.string.websites); List measurements = testResult.getMeasurementsSorted(); diff --git a/app/src/dw/assets/descriptors.json b/app/src/dw/assets/descriptors.json new file mode 100644 index 000000000..837ad582c --- /dev/null +++ b/app/src/dw/assets/descriptors.json @@ -0,0 +1,312 @@ +[ + { + "name": "Trusted International Media", + "short_description": "The most reliable international media outlets.", + "description": "In this list you will find the largest, most reliable international media outlets in the world.", + "author": "internet-freedom@dw.com", + "nettests": [ + { + "test_name": "web_connectivity", + "inputs": [ + "https://www.dw.com", + "https://www.francemediasmonde.com/", + "https://www.mc-doualiya.com/", + "https://www.dw.com/", + "https://www.bbc.com/", + "http://www.lemonde.fr/", + "https://www.rferl.org/", + "http://www.rfi.fr/", + "http://www.voanews.com/", + "https://ici.radio-canada.ca/rci/en", + "https://www.rfa.org/english/", + "https://www.france24.com/en/", + "https://www3.nhk.or.jp/nhkworld/", + "https://www.abc.net.au/news", + "https://www.swissinfo.ch/eng/", + "https://www.srgssr.ch/en/home/" + ], + "options": {}, + "backend_options": {}, + "is_background_run_enabled_default": false, + "is_manual_run_enabled_default": false + } + ], + "name_intl": { + "de": "Vertrauenswürdige Internationale Medien", + "en": "Trusted international media", + "ru": "Доверенные международные СМИ" + }, + "short_description_intl": {}, + "description_intl": {}, + "icon": "FaShield", + "color": "#68bc00", + "expiration_date": "2027-07-24T00:00:00.000000Z", + "oonirun_link_id": "10004", + "date_created": "2024-06-06T14:35:13.000000Z", + "date_updated": "2024-06-06T14:56:44.000000Z", + "revision": "2", + "is_mine": false, + "is_expired": false + }, + { + "name": "Selected (inter)national media", + "short_description": "Selected national and international media outlets.", + "description": "Selected national and international media outlets. \nWarning: This could also include biased and/or propagandistic media.", + "author": "internet-freedom@dw.com", + "nettests": [ + { + "test_name": "web_connectivity", + "inputs": [ + "https://dartcenter.org/", + "https://ourworldindata.org/", + "https://www.propublica.org/", + "http://www.1tv.ru/", + "http://www.vesti.ru/", + "https://sputnikglobe.com/", + "https://rtr-planeta.com/", + "https://www.ntv.ru/", + "https://www.rtarabic.com/", + "https://vgtrk.ru/", + "https://www.currenttime.tv/", + "https://www.dailywire.com/", + "https://timcast.com/", + "https://www.projectveritas.com/", + "https://www.francemediasmonde.com/", + "https://www.france24.com/ar/", + "https://www.mc-doualiya.com/", + "https://www.washingtonpost.com/", + "https://www.spiegel.de/", + "https://www.icij.org/", + "https://foreignpolicy.com/", + "https://www.reuters.com/", + "https://sputniknews.com/", + "https://www.sbs.com.au/language/coronavirus?cid=infocus", + "http://www.ftchinese.com/", + "http://www.sputniknews.cn/", + "http://www.dailymail.co.uk/", + "https://www.theatlantic.com/", + "https://www.nbcnews.com/", + "https://www.aljazeera.com/", + "https://www.urduvoa.com/", + "https://www.dw.com/", + "https://www.nbc.com/", + "http://abc.go.com/", + "https://theintercept.com/", + "https://www.bbc.com/", + "https://www.bbc.co.uk/", + "https://www.chinadaily.com.cn/", + "https://news.google.com/", + "https://nypost.com/", + "https://www.wsj.com/", + "https://timesofindia.indiatimes.com/", + "https://wikileaks.org/", + "https://www.afp.com/", + "https://www.alarabiya.net/", + "https://www.aljazeera.net/", + "https://www.cbc.ca/", + "https://www.cbsnews.com/", + "https://www.chinatimes.com/", + "https://edition.cnn.com/", + "https://www.foxnews.com/", + "https://www.ft.com/", + "http://www.granma.cu/", + "https://www.haaretz.com/", + "http://www.indiatimes.com/", + "http://www.irna.ir/", + "http://www.kcna.kp/", + "http://www.lemonde.fr/", + "http://www.mainichi.co.jp/", + "http://www.mizzima.com/", + "https://www.nytimes.com/", + "http://www.people.com.cn/", + "http://www.pravda.ru/", + "https://www.rambler.ru/", + "https://www.reddit.com/", + "http://www.repubblica.com/", + "https://www.rferl.org/", + "http://www.rfi.fr/", + "https://www.rt.com/", + "https://www.telegraph.co.uk/", + "http://www.theepochtimes.com/", + "https://www.theguardian.com/", + "http://www.voanews.com/", + "http://www.washingtontimes.com/", + "http://www.xinhuanet.com/", + "http://www.zeit.de/" + ], + "options": {}, + "backend_options": {}, + "is_background_run_enabled_default": false, + "is_manual_run_enabled_default": false + } + ], + "name_intl": {}, + "short_description_intl": {}, + "description_intl": {}, + "icon": "FaBookOpenReader", + "color": "#000000", + "expiration_date": "2027-07-24T00:00:00.000000Z", + "oonirun_link_id": "10005", + "date_created": "2024-06-06T14:37:53.000000Z", + "date_updated": "2024-06-06T14:37:53.000000Z", + "revision": "2", + "is_mine": false, + "is_expired": false + }, + { + "name": "Global media ", + "short_description": "A wide range of global media.", + "description": "This is the largest collection of media worldwide.\n\nAttention: This list will most likely contain propagandistic and influenced media outlets.", + "author": "internet-freedom@dw.com", + "nettests": [ + { + "test_name": "web_connectivity", + "inputs": [ + "https://dartcenter.org/", + "https://ourworldindata.org/", + "https://www.propublica.org/", + "https://www.vesti.ru/", + "http://ren.tv/", + "http://smotrim.ru/", + "http://www.1tv.ru/", + "http://www.tvc.ru/", + "http://www.vesti.ru/", + "https://sputnikglobe.com/", + "https://rtr-planeta.com/", + "https://www.ntv.ru/", + "https://www.rtarabic.com/", + "https://vgtrk.ru/", + "https://www.currenttime.tv/", + "http://www.freeexpression.org/", + "https://www.dailywire.com/", + "https://timcast.com/", + "https://wearechange.org/", + "https://reclaimthenet.org/", + "https://www.muckrock.com/", + "https://www.projectveritas.com/", + "https://substack.com/", + "https://www.infowars.com/", + "https://banthis.tv/", + "http://ria.ru/", + "https://www.francemediasmonde.com/", + "https://www.france24.com/ar/", + "https://www.mc-doualiya.com/", + "https://www.usatoday.com/", + "https://www.washingtonpost.com/", + "https://www.spiegel.de/", + "https://www.icij.org/", + "http://www.qhtyzx.com/", + "http://www.qhnews.com/", + "https://liveuamap.com/", + "https://foreignpolicy.com/", + "https://www.reuters.com/", + "https://sputniknews.com/", + "https://www.sbs.com.au/language/coronavirus?cid=infocus", + "http://www.ftchinese.com/", + "http://www.sputniknews.cn/", + "https://www.dailysabah.com/", + "http://www.dailymail.co.uk/", + "https://www.economist.com/", + "https://www.theatlantic.com/", + "https://www.nbcnews.com/", + "https://slate.com/", + "https://www.aljazeera.com/", + "https://globalpressjournal.com/", + "https://www.urduvoa.com/", + "https://www.dw.com/", + "https://www.vice.com/", + "https://tyt.com/", + "https://www.nbc.com/", + "http://abc.go.com/", + "https://theintercept.com/", + "https://www.bbc.com/", + "https://www.bbc.co.uk/", + "https://asiatimes.com/", + "https://boingboing.net/", + "https://www.chinadaily.com.cn/", + "https://creativecommons.org/", + "https://indymedia.org/", + "https://ipi.media/", + "https://jezebel.com/", + "http://www.kabobfest.com/", + "https://news.google.com/", + "https://nypost.com/", + "https://www.wsj.com/", + "http://russia.tv/", + "https://slashdot.org/", + "https://timesofindia.indiatimes.com/", + "https://wikileaks.org/", + "https://www.advocate.com/", + "https://www.afp.com/", + "https://www.ahram.org.eg/", + "https://www.alarabiya.net/", + "https://www.aljazeera.net/", + "https://www.almanar.com.lb/", + "https://www.arabnews.com/", + "https://www.benedelman.org/", + "https://www.cbc.ca/", + "https://www.cbsnews.com/", + "https://www.chinatimes.com/", + "https://edition.cnn.com/", + "https://www.csmonitor.com/", + "https://www.democracynow.org/", + "https://www.dopplr.com/", + "http://www.drudgereport.com/", + "https://www.eluniversal.com/", + "https://www.foxnews.com/", + "https://www.ft.com/", + "https://www.gearthblog.com/", + "http://www.granma.cu/", + "https://www.haaretz.com/", + "https://www.huffpost.com/", + "http://www.indiatimes.com/", + "http://www.irna.ir/", + "http://www.kcna.kp/", + "http://www.lanacion.com.ar/", + "http://www.latimes.com/", + "http://www.lemonde.fr/", + "http://www.mainichi.co.jp/", + "https://www.mideastyouth.com/", + "http://www.mizzima.com/", + "https://www.nytimes.com/", + "http://www.ohmynews.com/", + "http://www.osce.org/", + "http://www.people.com.cn/", + "http://www.pravda.ru/", + "https://www.rambler.ru/", + "https://www.reddit.com/", + "http://www.repubblica.com/", + "https://www.rferl.org/", + "http://www.rfi.fr/", + "https://www.rt.com/", + "https://www.telegraph.co.uk/", + "http://www.theepochtimes.com/", + "https://www.theguardian.com/", + "http://www.theregister.co.uk/", + "http://www.voanews.com/", + "http://www.washingtontimes.com/", + "http://www.wnd.com/", + "http://www.xinhuanet.com/", + "http://www.zeit.de/", + "http://xxx.lanl.gov/" + ], + "options": {}, + "backend_options": {}, + "is_background_run_enabled_default": false, + "is_manual_run_enabled_default": false + } + ], + "name_intl": {}, + "short_description_intl": {}, + "description_intl": {}, + "icon": "FaEarthAmericas", + "color": "#000000", + "expiration_date": "2027-07-24T00:00:00.000000Z", + "oonirun_link_id": "10006", + "date_created": "2024-06-06T14:39:02.000000Z", + "date_updated": "2024-06-06T14:39:02.000000Z", + "revision": "2", + "is_mine": false, + "is_expired": false + } +] \ No newline at end of file diff --git a/app/src/dw/kotlin/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt b/app/src/dw/kotlin/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt new file mode 100644 index 000000000..0e44b4ad1 --- /dev/null +++ b/app/src/dw/kotlin/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt @@ -0,0 +1,67 @@ +package org.openobservatory.ooniprobe.activity.runtests.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import org.openobservatory.ooniprobe.R +import org.openobservatory.ooniprobe.activity.runtests.RunTestsViewModel +import org.openobservatory.ooniprobe.activity.runtests.models.ChildItem +import org.openobservatory.ooniprobe.activity.runtests.models.GroupItem +import org.openobservatory.ooniprobe.test.test.AbstractTest + + +class RunTestsExpandableListViewAdapter( + private val groupedListData: List, + private val viewModel: RunTestsViewModel +) : AbstractRunTestsExpandableListViewAdapter(groupedListData, viewModel) { + + override fun getChildrenCount(groupPosition: Int): Int { + val group = groupedListData[groupPosition] + return if (group is GroupItem && group.nettests.isNotEmpty()) { + group.nettests[0].inputs?.size ?: 0 + } else { + 0 + } + } + + + override fun getChild(groupPosition: Int, childPosition: Int): ChildItem { + + return when (val group = groupedListData[groupPosition]) { + is GroupItem -> { + ChildItem( + name = group.nettests[0].inputs?.get(childPosition) + ?: "", + selected = false, + inputs = null + ) + } + + else -> ChildItem(name = "", selected = false, inputs = null) + } + } + + override fun getChildView( + groupPosition: Int, + childPosition: Int, + isLastChild: Boolean, + convertView: View?, + parent: ViewGroup + ): View? { + var convertView = + convertView + ?: LayoutInflater.from(parent.context) + .inflate(R.layout.run_tests_child_list_item, parent, false) + val childItem = getChild(groupPosition, childPosition) + convertView.findViewById(R.id.child_name)?.apply { + text = childItem.name + } + convertView.findViewById(R.id.child_select).apply { + visibility = View.GONE + } + convertView.setPadding(parent.context.resources.getDimensionPixelOffset(R.dimen.item_padding_prefix), 0, 0, 0) + return convertView + } +} \ No newline at end of file diff --git a/app/src/dw/kotlin/org/openobservatory/ooniprobe/common/DefaultDescriptors.kt b/app/src/dw/kotlin/org/openobservatory/ooniprobe/common/DefaultDescriptors.kt new file mode 100644 index 000000000..df9384b30 --- /dev/null +++ b/app/src/dw/kotlin/org/openobservatory/ooniprobe/common/DefaultDescriptors.kt @@ -0,0 +1,77 @@ +package org.openobservatory.ooniprobe.common + +import android.annotation.SuppressLint +import android.content.Context +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.raizlabs.android.dbflow.sql.language.SQLite +import org.openobservatory.engine.BaseNettest +import org.openobservatory.engine.OONIRunDescriptor +import org.openobservatory.ooniprobe.model.database.TestDescriptor +import org.openobservatory.ooniprobe.model.database.TestDescriptor_Table +import org.openobservatory.ooniprobe.model.database.Url +import org.openobservatory.ooniprobe.test.suite.DynamicTestSuite + +class DefaultDescriptors { + companion object { + + @SuppressLint("StringFormatInvalid") + @JvmStatic + fun getAll(context: Context): List> { + // NOTE: Performance hit since json is read and database checked every time this method is called. + context.assets.open("descriptors.json").use { inputStream -> + JsonReader(inputStream.reader()).use { jsonReader -> + // Read the json file and convert it to a list of OONIRunDescriptor. + val descriptorType = object : TypeToken>() {}.type + val descriptorList: List = + Gson().fromJson(jsonReader, descriptorType) + // Save the descriptors to the database. + descriptorList.forEach { ooniRunDescriptor -> + + // Check if the descriptor is already in the database. + ooniRunDescriptor.nettests.forEach { nettest -> + nettest.inputs?.forEach { input -> + Url.checkExistingUrl(input) + } + } + // Check if the descriptor is already in the database. + val testDescriptor = SQLite.select().from(TestDescriptor::class.java) + .where(TestDescriptor_Table.runId.eq(ooniRunDescriptor.oonirunLinkId.toLong())) + .querySingle() + // Save the descriptor if it is not in the database. + if (testDescriptor == null) { + ooniRunDescriptor.toTestDescriptor().apply { + + ooniRunDescriptor.nettests.forEach { nettest -> + (context as? Application)?.preferenceManager?.let { + it.enableTest(nettest.name, preferencePrefix()) + it.enableTest(nettest.name, preferencePrefix(),true) + } + } + + isAutoUpdate = true + }.save() + } + } + return emptyList() + } + } + } + + @JvmStatic + fun autoRunTests( + context: Context, + preferenceManager: PreferenceManager, + testDescriptorManager: TestDescriptorManager + ): MutableList { + return testDescriptorManager.getRunV2Descriptors(expired = false) + .map { testDescriptor -> + testDescriptor.toDynamicTestSuite(context).apply { + autoRun = true + } + }.toMutableList() + } + + } +} diff --git a/app/src/dw/res/drawable/ooni_phone.xml b/app/src/dw/res/drawable/ooni_phone.xml new file mode 100644 index 000000000..43a08e8d8 --- /dev/null +++ b/app/src/dw/res/drawable/ooni_phone.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/dw/res/layout/activity_prompt.xml b/app/src/dw/res/layout/activity_prompt.xml new file mode 100644 index 000000000..e4e37fb79 --- /dev/null +++ b/app/src/dw/res/layout/activity_prompt.xml @@ -0,0 +1,85 @@ + + + + + + + + + +