- * This method is called after the {@link ManualUpdateDescriptorsWorker} is enqueued.
- * The {@link ManualUpdateDescriptorsWorker} task is to fetch updates for the descriptors.
- *
- * This method is called after the {@link ManualUpdateDescriptorsWorker} is enqueued.
- * The {@link ManualUpdateDescriptorsWorker} task is to fetch updates for the descriptors.
- *
- * If the task is successful, the {@link WorkInfo} object will contain the updated descriptors.
- * Otherwise, the {@link WorkInfo} object will be null.
- *
- * @param workInfo The {@link WorkInfo} of the task.
- */
- private void onManualUpdatesFetchComplete(WorkInfo workInfo) {
- if (workInfo != null) {
- switch (workInfo.getState()) {
- case SUCCEEDED -> {
- binding.reviewUpdates.setVisibility(View.VISIBLE);
- binding.reviewUpdates.setOnClickListener(view -> getReviewUpdatesLauncher().launch(
- ReviewDescriptorUpdatesActivity.newIntent(
- OverviewActivity.this,
- workInfo.getOutputData().getString(ManualUpdateDescriptorsWorker.KEY_UPDATED_DESCRIPTORS)
- )
- ));
- binding.swipeRefresh.setRefreshing(false);
- }
-
- case FAILED -> {
- binding.swipeRefresh.setRefreshing(false);
- Snackbar.make(
- binding.getRoot(),
- R.string.Modal_Error,
- Snackbar.LENGTH_LONG
- ).show();
- }
-
- default -> {
- }
- }
- }
}
@Override
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/ReviewUpdatesAbstractActivity.kt b/app/src/main/java/org/openobservatory/ooniprobe/activity/ReviewUpdatesAbstractActivity.kt
deleted file mode 100644
index 5adff209b..000000000
--- a/app/src/main/java/org/openobservatory/ooniprobe/activity/ReviewUpdatesAbstractActivity.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.openobservatory.ooniprobe.activity
-
-import android.content.Intent
-import android.util.Log
-import android.view.View
-import androidx.activity.result.ActivityResult
-import androidx.activity.result.ActivityResultLauncher
-import androidx.activity.result.contract.ActivityResultContracts
-import com.google.android.material.snackbar.Snackbar
-import org.openobservatory.ooniprobe.activity.reviewdescriptorupdates.ReviewDescriptorUpdatesActivity
-
-open class ReviewUpdatesAbstractActivity : AbstractActivity() {
- var reviewUpdatesLauncher: ActivityResultLauncher? = null
-
- fun registerReviewLauncher(view: View, reviewCompletedListener: () -> Unit?) {
- reviewUpdatesLauncher =
- registerForActivityResult(ActivityResultContracts.StartActivityForResult())
- { result: ActivityResult ->
- if (result.resultCode == RESULT_OK) {
- reviewCompletedListener()
- result.data?.let { intent: Intent ->
- intent.getStringExtra(ReviewDescriptorUpdatesActivity.RESULT_MESSAGE)
- ?.let { message: String ->
- Snackbar.make(view, message, Snackbar.LENGTH_LONG)
- .setAnchorView(view).show()
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorActivity.kt b/app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorActivity.kt
index 6fedc19fd..5b2a0a8d8 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorActivity.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorActivity.kt
@@ -16,6 +16,9 @@ import androidx.databinding.BindingAdapter
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.noties.markwon.Markwon
+import org.openobservatory.engine.BaseNettest
+import org.openobservatory.engine.OONIRunDescriptor
+import org.openobservatory.engine.OONIRunNettest
import org.openobservatory.ooniprobe.R
import org.openobservatory.ooniprobe.activity.AbstractActivity
import org.openobservatory.ooniprobe.activity.MainActivity
@@ -82,19 +85,17 @@ class AddDescriptorActivity : AbstractActivity() {
* @param iconName is the name of the drawable resource
*/
@JvmStatic
- @BindingAdapter(value = ["resource","color"])
- fun setImageViewResource(imageView: ImageView, iconName: String?, color: Int?) {
+ @BindingAdapter(value = ["resource"])
+ fun setImageViewResource(imageView: ImageView, iconName: String?) {
+ /* TODO(aanorbel): Update to parse the icon name and set the correct icon.
+ * Remember to ignore icons generated when generated doing this.*/
imageView.setImageResource(
imageView.context.resources.getIdentifier(
StringUtils.camelToSnake(
iconName
), "drawable", imageView.context.packageName
)
- ).apply {
- color?.let {
- imageView.setColorFilter(it)
- }
- }
+ )
}
}
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorViewModel.kt b/app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorViewModel.kt
index e0362696c..90d25ec08 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorViewModel.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/adddescriptor/AddDescriptorViewModel.kt
@@ -1,11 +1,11 @@
package org.openobservatory.ooniprobe.activity.adddescriptor
-import android.graphics.Color
-import androidx.annotation.ColorInt
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.google.android.material.checkbox.MaterialCheckBox
import com.google.android.material.checkbox.MaterialCheckBox.CheckedState
+import org.openobservatory.engine.OONIRunDescriptor
+import org.openobservatory.engine.OONIRunNettest
import org.openobservatory.ooniprobe.activity.adddescriptor.adapter.GroupedItem
import org.openobservatory.ooniprobe.common.LocaleUtils
import org.openobservatory.ooniprobe.common.TestDescriptorManager
@@ -38,10 +38,6 @@ class AddDescriptorViewModel constructor(
this.descriptor.value = descriptor
}
- @ColorInt
- fun getColor(): Int {
- return Color.parseColor( descriptor.value?.color ?: "#495057")
- }
/**
* This method is used to get the name of the descriptor.
* Used by the UI during data binding.
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/oonirun/OoniRunV2Activity.kt b/app/src/main/java/org/openobservatory/ooniprobe/activity/oonirun/OoniRunV2Activity.kt
index b5a092621..5b4dc61bc 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/activity/oonirun/OoniRunV2Activity.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/oonirun/OoniRunV2Activity.kt
@@ -134,7 +134,7 @@ class OoniRunV2Activity : AbstractActivity() {
descriptorResponse?.let {
startActivity(AddDescriptorActivity.newIntent(this, descriptorResponse))
} ?: run {
- finishWithError()
+ Toast.makeText(this, getString(R.string.Modal_Error), Toast.LENGTH_LONG).show()
}
}
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/reviewdescriptorupdates/ReviewDescriptorUpdatesActivity.kt b/app/src/main/java/org/openobservatory/ooniprobe/activity/reviewdescriptorupdates/ReviewDescriptorUpdatesActivity.kt
deleted file mode 100644
index ebe32bd45..000000000
--- a/app/src/main/java/org/openobservatory/ooniprobe/activity/reviewdescriptorupdates/ReviewDescriptorUpdatesActivity.kt
+++ /dev/null
@@ -1,364 +0,0 @@
-package org.openobservatory.ooniprobe.activity.reviewdescriptorupdates
-
-import android.content.Context
-import android.content.Intent
-import android.os.Build
-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.BaseExpandableListAdapter
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.appcompat.widget.Toolbar
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.viewpager2.adapter.FragmentStateAdapter
-import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
-import com.google.android.material.checkbox.MaterialCheckBox
-import com.google.android.material.snackbar.Snackbar
-import com.google.gson.Gson
-import com.google.gson.internal.LinkedTreeMap
-import org.openobservatory.engine.BaseNettest
-import org.openobservatory.ooniprobe.R
-import org.openobservatory.ooniprobe.activity.AbstractActivity
-import org.openobservatory.ooniprobe.common.TestDescriptorManager
-import org.openobservatory.ooniprobe.databinding.ActivityReviewDescriptorUpdatesBinding
-import org.openobservatory.ooniprobe.databinding.FragmentDescriptorUpdateBinding
-import org.openobservatory.ooniprobe.model.database.ITestDescriptor
-import org.openobservatory.ooniprobe.model.database.InstalledDescriptor
-import org.openobservatory.ooniprobe.model.database.TestDescriptor
-import org.openobservatory.ooniprobe.test.test.AbstractTest
-import java.text.SimpleDateFormat
-import java.util.Locale
-import javax.inject.Inject
-
-/**
- * This activity is used to review the updates of the descriptors.
- * When a new update is available, the user is prompted to review the changes.
- * This activity is started by the [org.openobservatory.ooniprobe.activity.MainActivity] activity.
- */
-class ReviewDescriptorUpdatesActivity : AbstractActivity() {
-
- companion object {
- private const val DESCRIPTORS = "descriptors"
-
- @JvmField
- var RESULT_MESSAGE = "result"
-
- /**
- * This method is used to create an intent to start this activity.
- * @param context is the context of the activity that calls this method
- * @param descriptors is the descriptors to review
- * @return an intent to start this activity
- */
- @JvmStatic
- fun newIntent(context: Context, descriptors: String?): Intent {
- return Intent(context, ReviewDescriptorUpdatesActivity::class.java).putExtra(
- DESCRIPTORS,
- descriptors
- )
- }
- }
-
- @Inject
- lateinit var descriptorManager: TestDescriptorManager
-
- @Inject
- lateinit var gson: Gson
-
- private lateinit var reviewUpdatesPagingAdapter: ReviewUpdatesPagingAdapter
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- activityComponent.inject(this)
- val binding = ActivityReviewDescriptorUpdatesBinding.inflate(layoutInflater)
- setContentView(binding.root)
- setSupportActionBar(binding.toolbar)
- supportActionBar?.setDisplayHomeAsUpEnabled(false)
- supportActionBar?.setDisplayShowHomeEnabled(false)
- supportActionBar?.title = "Link Update"
- val descriptorJson = intent.getStringExtra(DESCRIPTORS)
- try {
- /**
- * **[descriptorJson]** is the json string of the intent.
- * **[descriptors]** is the list of [TestDescriptor] objects obtained from **[descriptorJson]**.
- * Because [TestDescriptor.nettests] is of type [Any], the gson library converts it to a [LinkedTreeMap].
- */
- val descriptors: List =
- gson.fromJson(descriptorJson, Array::class.java)
- .map { it.toTestDescriptor() }
-
- // Disable swipe behavior of viewpager
- binding.viewpager.isUserInputEnabled = false
-
- reviewUpdatesPagingAdapter = ReviewUpdatesPagingAdapter(this, descriptors)
- binding.viewpager.adapter = reviewUpdatesPagingAdapter
-
- /**
- * The bottom bar menu item click listener.
- * When the user clicks on the update button, the viewpager is swiped to the next page.
- * When the user clicks on the last update, the activity is finished.
- */
- val bottomBarOnMenuItemClickListener: Toolbar.OnMenuItemClickListener =
- Toolbar.OnMenuItemClickListener { item ->
- when (item.itemId) {
- R.id.update_descriptor -> {
- descriptorManager.updateFromNetwork(descriptors[binding.viewpager.currentItem])
- /**
- * **[currPos]** is the current position of the viewpager.
- * If the current position is not the last position, the viewpager is swiped to the next page.
- * If the current position is the last position, the last update is saved in the shared preferences and the activity is finished.
- */
- val currPos: Int = binding.viewpager.currentItem
- if ((currPos + 1) != binding.viewpager.adapter?.itemCount) {
- binding.viewpager.currentItem = currPos + 1
- } else {
- setResult(RESULT_OK, Intent().putExtra(RESULT_MESSAGE, "Link(s) updated"))
- finish()
- }
- true
- }
-
- else -> false
- }
- }
- binding.bottomBar.setOnMenuItemClickListener(bottomBarOnMenuItemClickListener)
-
- /**
- * The viewpager page change callback.
- * When the user swipes to the next page, the bottom bar menu item title is updated.
- */
- binding.viewpager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
- override fun onPageSelected(position: Int) {
- binding.bottomBar.menu.findItem(R.id.update_descriptor)
- ?.let {
- val countString =
- "(${position + 1} of ${binding.viewpager.adapter?.itemCount})"
- supportActionBar?.title = "Link Update $countString"
- it.title = if ((position + 1) != binding.viewpager.adapter?.itemCount) {
- "UPDATE $countString"
- } else {
- "UPDATE AND FINISH $countString"
- }
- }
-
- }
- })
-
- } catch (e: Exception) {
- finish()
- }
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- val inflater: MenuInflater = menuInflater
- inflater.inflate(R.menu.close, menu)
- return true
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- R.id.close_button -> {
- finish()
- true
- }
-
- else -> super.onOptionsItemSelected(item)
- }
- }
-}
-
-/**
- * This adapter is used to display the list of descriptors in the viewpager.
- * @param fragmentActivity is the activity that contains the viewpager.
- * @param descriptors is the list of descriptors to display.
- */
-class ReviewUpdatesPagingAdapter(
- fragmentActivity: FragmentActivity,
- private val descriptors: List
-) : FragmentStateAdapter(fragmentActivity) {
- override fun getItemCount(): Int = descriptors.size
-
- override fun createFragment(position: Int): Fragment {
- val fragment = DescriptorUpdateFragment()
- fragment.arguments = Bundle().apply {
- putSerializable(DESCRIPTOR, descriptors[position])
- }
- return fragment
- }
-}
-
-private const val DESCRIPTOR = "descriptor"
-
-/**
- * This fragment is used to display the details of a descriptor.
- * It is used by [ReviewUpdatesPagingAdapter].
- * @param descriptor is the descriptor to display.
- */
-class DescriptorUpdateFragment : Fragment() {
-
- private lateinit var binding: FragmentDescriptorUpdateBinding
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- binding = FragmentDescriptorUpdateBinding.inflate(inflater, container, false)
- return binding.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- arguments?.takeIf { it.containsKey(DESCRIPTOR) }?.apply {
- val descriptor: TestDescriptor =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- getSerializable(DESCRIPTOR, TestDescriptor::class.java)!!
- } else {
- getSerializable(DESCRIPTOR) as TestDescriptor
- }
- val absDescriptor = InstalledDescriptor(descriptor)
- binding.apply {
- title.text = absDescriptor.title
- author.text = "Created by ${descriptor.author} on ${
- SimpleDateFormat(
- "MMM dd, yyyy",
- Locale.getDefault()
- ).format(descriptor.descriptorCreationTime)
- }"
- description.text = absDescriptor.description // Use markdown
- icon.setImageResource(absDescriptor.getDisplayIcon(requireContext()))
- val adapter =
- ReviewDescriptorExpandableListAdapter(nettests = absDescriptor.nettests)
- expandableListView.setAdapter(adapter)
- // Expand all groups
- for (i in 0 until adapter.groupCount) {
- expandableListView.expandGroup(i)
- }
- }
- }
- }
-}
-
-/**
- * This adapter is used to display the list of nettests in the expandable list view.
- * It is used by [DescriptorUpdateFragment] to display the list of nettests.
- * @param nettests is the list of nettests to display.
- */
-class ReviewDescriptorExpandableListAdapter(
- val nettests: List,
-) : BaseExpandableListAdapter() {
-
- /**
- * @return Number of groups in the list.
- */
- override fun getGroupCount(): Int = nettests.size
-
- /**
- * @param groupPosition Position of the group in the list.
- * @return Number of children in the group.
- */
- override fun getChildrenCount(groupPosition: Int): Int =
- nettests[groupPosition].inputs?.size ?: 0
-
- /**
- * @param groupPosition Position of the group in the list.
- * @return [BaseNettest] object.
- */
- override fun getGroup(groupPosition: Int): BaseNettest = nettests[groupPosition]
-
- /**
- * @param groupPosition Position of the group in the list.
- * @param childPosition Position of the child in the group.
- * @return string item at position.
- */
- override fun getChild(groupPosition: Int, childPosition: Int): String? =
- nettests[groupPosition].inputs?.get(childPosition)
-
- /**
- * @param groupPosition Position of the group in the list.
- * @return Group position.
- */
- override fun getGroupId(groupPosition: Int): Long = groupPosition.toLong()
-
- /**
- * @param groupPosition Position of the group in the list.
- * @param childPosition Position of the child in the group.
- * @return Child position.
- */
- override fun getChildId(groupPosition: Int, childPosition: Int): Long = childPosition.toLong()
-
- /**
- * @return true if the same ID always refers to the same object.
- */
- override fun hasStableIds(): Boolean = false
-
- /**
- * @param groupPosition Position of the group in the list.
- * @param isExpanded true if the group is expanded.
- * @param convertView View of the group.
- * @param parent Parent view.
- * @return View of the group.
- */
- override fun getGroupView(
- groupPosition: Int,
- isExpanded: Boolean,
- convertView: View?,
- parent: ViewGroup,
- ): View {
- val view = convertView ?: LayoutInflater.from(parent.context)
- .inflate(R.layout.nettest_group_list_item, parent, false)
- val groupItem = getGroup(groupPosition)
- val groupIndicator = view.findViewById(R.id.group_indicator)
-
- val abstractNettest = AbstractTest.getTestByName(groupItem.name)
- view.findViewById(R.id.group_name).text =
- when (abstractNettest.labelResId == R.string.Test_Experimental_Fullname) {
- true -> groupItem.name
- false -> parent.context.resources.getText(abstractNettest.labelResId)
- }
-
- val groupCheckBox = view.findViewById(R.id.groupCheckBox)
- groupCheckBox.visibility = View.GONE
- if (groupItem.inputs?.isNotEmpty() == true) {
- if (isExpanded) {
- groupIndicator.setImageResource(R.drawable.expand_less)
- } else {
- groupIndicator.setImageResource(R.drawable.expand_more)
- }
- } else {
- groupIndicator.visibility = View.INVISIBLE
- }
-
- return view
- }
-
- /**
- * @param groupPosition Position of the group in the list.
- * @param childPosition Position of the child in the group.
- * @param isLastChild True if the child is the last child in the group.
- * @param convertView View object.
- * @param parent ViewGroup object.
- * @return View object.
- */
- override fun getChildView(
- groupPosition: Int,
- childPosition: Int,
- isLastChild: Boolean,
- convertView: View?,
- parent: ViewGroup
- ): View {
- val view = convertView ?: LayoutInflater.from(parent.context)
- .inflate(R.layout.nettest_child_list_item, parent, false)
-
- view.findViewById(R.id.text).apply {
- text = getChild(groupPosition, childPosition)
- }
- return view
- }
-
- override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean = false
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt b/app/src/main/java/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt
index 5c94b71c3..59fe79b54 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt
@@ -8,11 +8,12 @@ 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.RunTestsViewModel.Companion.SELECT_ALL
import org.openobservatory.ooniprobe.activity.runtests.RunTestsViewModel.Companion.SELECT_NONE
+import org.openobservatory.ooniprobe.activity.runtests.RunTestsViewModel.Companion.SELECT_ALL
import org.openobservatory.ooniprobe.activity.runtests.RunTestsViewModel.Companion.SELECT_SOME
import org.openobservatory.ooniprobe.activity.runtests.models.ChildItem
import org.openobservatory.ooniprobe.activity.runtests.models.GroupItem
+import org.openobservatory.ooniprobe.common.OONITests
import org.openobservatory.ooniprobe.test.test.AbstractTest
@@ -82,9 +83,7 @@ class RunTestsExpandableListViewAdapter(
convertView ?: LayoutInflater.from(parent.context).inflate(R.layout.run_tests_group_list_item, parent, false)
val groupItem = getGroup(groupPosition)
convertView.findViewById(R.id.group_name).text = groupItem.title
- val icon = convertView.findViewById(R.id.group_icon)
- icon.setImageResource(groupItem.getDisplayIcon(parent.context))
- icon.setColorFilter(groupItem.color)
+ convertView.findViewById(R.id.group_icon).setImageResource(groupItem.getDisplayIcon(parent.context))
val groupIndicator = convertView.findViewById(R.id.group_indicator)
val groupSelectionIndicator = convertView.findViewById(R.id.group_select_indicator)
val selectedAllBtnStatus = viewModel.selectedAllBtnStatus.getValue()
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/adapters/DashboardAdapter.kt b/app/src/main/java/org/openobservatory/ooniprobe/adapters/DashboardAdapter.kt
index de625836c..a731b0cff 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/adapters/DashboardAdapter.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/adapters/DashboardAdapter.kt
@@ -62,10 +62,8 @@ class DashboardAdapter(
icon.setImageResource(item.getDisplayIcon(holder.itemView.context)).also {
if (item is InstalledDescriptor){
icon.setColorFilter(item.color)
- holder.setIsRecyclable(false)
}
- }
- }
+ } }
holder.itemView.tag = item
if (!item.isEnabled(preferenceManager)) {
holder.setIsRecyclable(false)
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/OONIDescriptor.kt b/app/src/main/java/org/openobservatory/ooniprobe/common/OONIDescriptor.kt
index e67604108..7d446fdb9 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/common/OONIDescriptor.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/common/OONIDescriptor.kt
@@ -42,7 +42,7 @@ abstract class AbstractDescriptor(
* @param preferenceManager The [PreferenceManager] instance used to resolve the status of each nettest.
* @return Boolean Returns true if at least one nettest is enabled, false otherwise.
*/
- open fun isEnabled(preferenceManager: PreferenceManager): Boolean {
+ open fun isEnabled(preferenceManager: PreferenceManager): Boolean {
return when (name) {
OONITests.EXPERIMENTAL.label -> preferenceManager.isExperimentalOn
OONITests.WEBSITES.label -> preferenceManager.countEnabledCategory() > 0
@@ -136,7 +136,7 @@ abstract class AbstractDescriptor(
)
} ?: listOf())
},
- descriptor = this.descriptor
+ descriptor = descriptor
)
}
@@ -171,8 +171,8 @@ abstract class AbstractDescriptor(
* @return String representing the preference prefix.
*/
fun preferencePrefix(): String {
- return when (this.descriptor?.runId != null) {
- true -> this.descriptor?.preferencePrefix() ?: ""
+ return when (descriptor?.runId != null) {
+ true -> descriptor?.preferencePrefix() ?: ""
else -> ""
}
}
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/TestDescriptorManager.kt b/app/src/main/java/org/openobservatory/ooniprobe/common/TestDescriptorManager.kt
index 338ec6249..d0e301ec8 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/common/TestDescriptorManager.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/common/TestDescriptorManager.kt
@@ -100,11 +100,6 @@ class TestDescriptorManager @Inject constructor(
return descriptor.save()
}
- fun getById(runId: Long): TestDescriptor? {
- return SQLite.select().from(TestDescriptor::class.java)
- .where(TestDescriptor_Table.runId.eq(runId)).querySingle()
- }
-
fun getRunV2Descriptors(): List {
return SQLite.select().from(TestDescriptor::class.java)
.where(TestDescriptor_Table.isArchived.eq(false)).queryList()
@@ -122,29 +117,4 @@ class TestDescriptorManager @Inject constructor(
descriptor.testDescriptor.delete()
}
}
-
- fun getDescriptorWithAutoUpdateEnabled(): List {
- return SQLite.select().from(TestDescriptor::class.java)
- .where(TestDescriptor_Table.auto_update.eq(true)).queryList()
- }
-
- fun getDescriptorWithAutoUpdateDisabled(): List {
- return SQLite.select().from(TestDescriptor::class.java)
- .where(TestDescriptor_Table.auto_update.eq(false)).queryList()
- }
-
- fun updateFromNetwork(testDescriptor: TestDescriptor): Boolean {
- getById(testDescriptor.runId)?.let { descriptor ->
- testDescriptor.isAutoUpdate = descriptor.isAutoUpdate
- return testDescriptor.save()
- } ?: run {
- return false
- }
- }
-
- fun getDescriptorsFromIds(ids: Array): List {
- return SQLite.select().from(TestDescriptor::class.java)
- .where(TestDescriptor_Table.runId.`in`(ids.toList()))
- .queryList()
- }
}
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/worker/UpdateDescriptorsWorker.kt b/app/src/main/java/org/openobservatory/ooniprobe/common/worker/UpdateDescriptorsWorker.kt
deleted file mode 100644
index ae9d7135b..000000000
--- a/app/src/main/java/org/openobservatory/ooniprobe/common/worker/UpdateDescriptorsWorker.kt
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.openobservatory.ooniprobe.common.worker
-
-import android.content.Context
-import android.util.Log
-import androidx.work.Data
-import androidx.work.Worker
-import androidx.work.WorkerParameters
-import org.openobservatory.ooniprobe.common.Application
-import org.openobservatory.ooniprobe.common.PreferenceManager
-import org.openobservatory.ooniprobe.common.TestDescriptorManager
-import org.openobservatory.ooniprobe.common.ThirdPartyServices
-import org.openobservatory.ooniprobe.model.database.TestDescriptor
-import org.openobservatory.ooniprobe.model.database.shouldUpdate
-import javax.inject.Inject
-
-var d: UpdateDescriptorsWorkerDependencies = UpdateDescriptorsWorkerDependencies()
-const val PROGRESS = "PROGRESS"
-
-class AutoUpdateDescriptorsWorker(
- context: Context,
- workerParams: WorkerParameters
-) : Worker(context, workerParams) {
-
- override fun doWork(): Result {
- val app = applicationContext.applicationContext as Application
- app.serviceComponent.inject(d)
- return try {
- Log.d(TAG, "Fetching descriptors from input")
-
- val updatedDescriptors: ArrayList = ArrayList()
-
- for (descriptor in d.testDescriptorManager.getDescriptorWithAutoUpdateEnabled()) {
- Log.d(TAG, "Fetching updates for ${descriptor.runId}")
-
- val updatedDescriptor: TestDescriptor =
- d.testDescriptorManager.fetchDescriptorFromRunId(
- descriptor.runId,
- applicationContext
- )
-
- if (descriptor.shouldUpdate(updatedDescriptor)) {
- updatedDescriptor.isAutoUpdate = descriptor.isAutoUpdate
- updatedDescriptor.isAutoRun = descriptor.isAutoRun
-
- Log.d(TAG, "Saving updates for ${descriptor.runId}")
-
- updatedDescriptor.save()
- updatedDescriptors.add(updatedDescriptor)
- }
- }
-
- val outputData = Data.Builder()
- .putString(
- KEY_UPDATED_DESCRIPTORS,
- (applicationContext as Application).gson.toJson(updatedDescriptors)
- ).build()
-
- Log.e(TAG, "Descriptor updates complete")
-
- Result.success(outputData)
-
- } catch (exception: Exception) {
- Log.e(TAG, "Error Updating")
- exception.printStackTrace()
- ThirdPartyServices.logException(exception)
- Result.failure()
- }
- }
-
- companion object {
- @JvmField
- var UPDATED_DESCRIPTORS_WORK_NAME =
- "${AutoUpdateDescriptorsWorker::class.java.name}.UPDATED_DESCRIPTORS_WORK_NAME"
-
- private val TAG = AutoUpdateDescriptorsWorker::class.java.simpleName
-
- private val UPDATE_DESCRIPTOR_CHANNEL: String =
- AutoUpdateDescriptorsWorker::class.java.simpleName
-
- private val KEY_UPDATED_DESCRIPTORS =
- "${AutoUpdateDescriptorsWorker::class.java.name}.KEY_UPDATED_DESCRIPTORS"
- }
-}
-
-class ManualUpdateDescriptorsWorker(
- context: Context,
- workerParams: WorkerParameters
-) : Worker(context, workerParams) {
-
- override fun doWork(): Result {
-
- setProgressAsync(Data.Builder().putInt(PROGRESS, 0).build())
-
- val app = applicationContext.applicationContext as Application
- app.serviceComponent.inject(d)
-
- return try {
- Log.d(TAG, "Fetching descriptors from input")
-
- val updatedDescriptors: ArrayList = ArrayList()
-
- val descriptors = inputData.getLongArray(KEY_DESCRIPTOR_IDS)?.let {
- d.testDescriptorManager.getDescriptorsFromIds(it.toTypedArray())
- }.run {
- d.testDescriptorManager.getDescriptorWithAutoUpdateDisabled()
- }
-
- if(descriptors.isEmpty()) {
- Log.e(TAG, "No descriptors to update")
- return Result.success()
- }
-
- for (descriptor in descriptors) {
- Log.d(TAG, "Fetching updates for ${descriptor.runId}")
-
- val updatedDescriptor: TestDescriptor =
- d.testDescriptorManager.fetchDescriptorFromRunId(
- descriptor.runId,
- applicationContext
- )
- /**
- * NOTE(aanorbel): Refine this logic to only update if the descriptor has changed.
- * Consider explicit version compare.
- */
- if (descriptor.shouldUpdate(updatedDescriptor)) {
- updatedDescriptors.add(updatedDescriptor)
- }
- }
- val outputData = Data.Builder()
- .putString(
- KEY_UPDATED_DESCRIPTORS,
- (applicationContext as Application).gson.toJson(updatedDescriptors)
- ).build()
-
- Log.e(TAG, "fetching updates complete")
-
- setProgressAsync(Data.Builder().putInt(PROGRESS, 100).build())
- Result.success(outputData)
-
- } catch (exception: Exception) {
- Log.e(TAG, "Error Updating")
- exception.printStackTrace()
- ThirdPartyServices.logException(exception)
- Result.failure()
- }
- }
-
- companion object {
- @JvmField
- var UPDATED_DESCRIPTORS_WORK_NAME =
- "${AutoUpdateDescriptorsWorker::class.java.name}.UPDATED_DESCRIPTORS_WORK_NAME"
-
- private val TAG = AutoUpdateDescriptorsWorker::class.java.simpleName
-
- private val UPDATE_DESCRIPTOR_CHANNEL: String =
- AutoUpdateDescriptorsWorker::class.java.simpleName
-
- @JvmField
- var KEY_UPDATED_DESCRIPTORS =
- "${AutoUpdateDescriptorsWorker::class.java.name}.KEY_UPDATED_DESCRIPTORS"
- @JvmField
- var KEY_DESCRIPTOR_IDS =
- "${AutoUpdateDescriptorsWorker::class.java.name}.KEY_DESCRIPTOR_IDS"
- }
-}
-
-class UpdateDescriptorsWorkerDependencies {
- @Inject
- lateinit var testDescriptorManager: TestDescriptorManager
-
- @Inject
- lateinit var preferenceManager: PreferenceManager
-}
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/di/ActivityComponent.java b/app/src/main/java/org/openobservatory/ooniprobe/di/ActivityComponent.java
index 3377b50d7..4ed40d976 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/di/ActivityComponent.java
+++ b/app/src/main/java/org/openobservatory/ooniprobe/di/ActivityComponent.java
@@ -1,6 +1,8 @@
package org.openobservatory.ooniprobe.di;
+import org.openobservatory.ooniprobe.activity.adddescriptor.AddDescriptorActivity;
+import org.openobservatory.ooniprobe.activity.customwebsites.CustomWebsiteActivity;
import org.openobservatory.ooniprobe.activity.LogActivity;
import org.openobservatory.ooniprobe.activity.MainActivity;
import org.openobservatory.ooniprobe.activity.MeasurementDetailActivity;
@@ -8,13 +10,10 @@
import org.openobservatory.ooniprobe.activity.OverviewActivity;
import org.openobservatory.ooniprobe.activity.ProxyActivity;
import org.openobservatory.ooniprobe.activity.ResultDetailActivity;
-import org.openobservatory.ooniprobe.activity.RunningActivity;
-import org.openobservatory.ooniprobe.activity.TextActivity;
-import org.openobservatory.ooniprobe.activity.adddescriptor.AddDescriptorActivity;
-import org.openobservatory.ooniprobe.activity.customwebsites.CustomWebsiteActivity;
import org.openobservatory.ooniprobe.activity.oonirun.OoniRunV2Activity;
-import org.openobservatory.ooniprobe.activity.reviewdescriptorupdates.ReviewDescriptorUpdatesActivity;
import org.openobservatory.ooniprobe.activity.runtests.RunTestsActivity;
+import org.openobservatory.ooniprobe.activity.RunningActivity;
+import org.openobservatory.ooniprobe.activity.TextActivity;
import org.openobservatory.ooniprobe.di.annotations.PerActivity;
import dagger.Subcomponent;
@@ -24,7 +23,6 @@
public interface ActivityComponent {
void inject(OoniRunV2Activity activity);
void inject(AddDescriptorActivity activity);
- void inject(ReviewDescriptorUpdatesActivity activity);
void inject(CustomWebsiteActivity activity);
void inject(MainActivity activity);
void inject(ProxyActivity activity);
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/di/ServiceComponent.java b/app/src/main/java/org/openobservatory/ooniprobe/di/ServiceComponent.java
index ab6e4c85c..8ebf524ef 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/di/ServiceComponent.java
+++ b/app/src/main/java/org/openobservatory/ooniprobe/di/ServiceComponent.java
@@ -3,7 +3,6 @@
import org.openobservatory.ooniprobe.common.ResubmitTask;
import org.openobservatory.ooniprobe.common.service.RunTestJobService;
import org.openobservatory.ooniprobe.common.service.ServiceUtil;
-import org.openobservatory.ooniprobe.common.worker.UpdateDescriptorsWorkerDependencies;
import org.openobservatory.ooniprobe.di.annotations.PerService;
import dagger.Subcomponent;
@@ -14,5 +13,4 @@ public interface ServiceComponent {
void inject(ResubmitTask.Dependencies dependencies);
void inject(RunTestJobService service);
void inject(ServiceUtil.Dependencies dependencies);
- void inject(UpdateDescriptorsWorkerDependencies dependencies);
}
\ No newline at end of file
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/DashboardFragment.kt b/app/src/main/java/org/openobservatory/ooniprobe/fragment/DashboardFragment.kt
index 426600f89..0e6ca912b 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/DashboardFragment.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/DashboardFragment.kt
@@ -12,7 +12,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import org.openobservatory.engine.BaseNettest
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.runtests.RunTestsActivity
import org.openobservatory.ooniprobe.adapters.DashboardAdapter
@@ -86,11 +85,6 @@ class DashboardFragment : Fragment(), View.OnClickListener {
binding.lastTested.visibility = View.VISIBLE
}
}
-
- binding.swipeRefresh.setOnRefreshListener {
- (requireActivity() as MainActivity).fetchManualUpdate()
- binding.swipeRefresh.isRefreshing = false
- }
}
override fun onResume() {
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/fragment/dynamicprogressbar/OONIRunDynamicProgressBar.kt b/app/src/main/java/org/openobservatory/ooniprobe/fragment/dynamicprogressbar/OONIRunDynamicProgressBar.kt
index d8b5ef61e..91f9adaec 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/fragment/dynamicprogressbar/OONIRunDynamicProgressBar.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/fragment/dynamicprogressbar/OONIRunDynamicProgressBar.kt
@@ -54,7 +54,6 @@ class OONIRunDynamicProgressBar : Fragment() {
ProgressType.REVIEW_LINK -> {
binding.progressBar.visibility = View.GONE
binding.iconButton.visibility = View.VISIBLE
- binding.actionButton.text = "Review"
binding.progressText.text = "Link updates ready"
}
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/model/database/TestDescriptor.kt b/app/src/main/java/org/openobservatory/ooniprobe/model/database/TestDescriptor.kt
index daef1ca8e..8e66dbefa 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/model/database/TestDescriptor.kt
+++ b/app/src/main/java/org/openobservatory/ooniprobe/model/database/TestDescriptor.kt
@@ -17,8 +17,8 @@ import org.openobservatory.ooniprobe.activity.runtests.models.ChildItem
import org.openobservatory.ooniprobe.activity.runtests.models.GroupItem
import org.openobservatory.ooniprobe.common.AbstractDescriptor
import org.openobservatory.ooniprobe.common.AppDatabase
+import org.openobservatory.ooniprobe.common.OONITests
import org.openobservatory.ooniprobe.common.PreferenceManager
-import org.openobservatory.ooniprobe.common.resolveStatus
import java.io.Serializable
import java.util.Date
import com.raizlabs.android.dbflow.annotation.TypeConverter as TypeConverterAnnotation
@@ -65,19 +65,7 @@ class TestDescriptor(
}
}
-/**
- * Check if the descriptor should be updated based on the creation time of the descriptor and the creation time of the translations.
- *
- * @param updatedDescriptor The updated descriptor
- * @return True if the descriptor should be updated based on the creation time of the descriptor and the creation time of the translations.
- */
-fun TestDescriptor.shouldUpdate(updatedDescriptor: TestDescriptor): Boolean {
- return (updatedDescriptor.descriptorCreationTime?.after(descriptorCreationTime) ?: true
- || updatedDescriptor.translationCreationTime?.after(translationCreationTime) ?: true)
-}
-
private const val DESCRIPTOR_TEST_NAME = "ooni_run"
-
class InstalledDescriptor(
var testDescriptor: TestDescriptor
) : AbstractDescriptor(
@@ -101,7 +89,7 @@ class InstalledDescriptor(
false -> emptyList()
},
- descriptor = testDescriptor) {
+ descriptor = testDescriptor ) {
override fun isEnabled(preferenceManager: PreferenceManager): Boolean {
return !testDescriptor.isArchived
@@ -124,13 +112,13 @@ class InstalledDescriptor(
dataUsage = this.dataUsage,
nettests = this.nettests.map { nettest ->
ChildItem(
- selected = preferenceManager.resolveStatus(
- name = nettest.name,
- prefix = preferencePrefix(),
- ), name = nettest.name, inputs = nettest.inputs
+ selected = when (this.name == OONITests.EXPERIMENTAL.label) {
+ true -> preferenceManager.isExperimentalOn
+ false -> preferenceManager.resolveStatus(nettest.name)
+ }, name = nettest.name, inputs = nettest.inputs
)
},
- descriptor = this.testDescriptor
+ descriptor = testDescriptor
)
}
@@ -184,61 +172,3 @@ class NettestConverter : TypeConverter() {
).toList()
}
-class ITestDescriptor(
-
- var runId: Long = 0,
-
- var name: String = "",
-
- var nameIntl: HashMap? = null,
-
- var author: String = "",
-
- var shortDescription: String = "",
-
- var shortDescriptionIntl: HashMap? = null,
-
- var description: String = "",
-
- var descriptionIntl: HashMap? = null,
-
- var icon: String? = null,
-
- var color: String? = null,
-
- var animation: String? = null,
-
- var isArchived: Boolean = false,
-
- var isAutoRun: Boolean = true,
-
- var isAutoUpdate: Boolean = false,
-
- var descriptorCreationTime: Date? = null,
-
- var translationCreationTime: Date? = null,
-
- var nettests: List? = emptyList()
-) : Serializable {
- fun toTestDescriptor(): TestDescriptor {
- return TestDescriptor(
- runId = runId,
- name = name,
- nameIntl = nameIntl,
- author = author,
- shortDescription = shortDescription,
- shortDescriptionIntl = shortDescriptionIntl,
- description = description,
- descriptionIntl = descriptionIntl,
- icon = icon,
- color = color,
- animation = animation,
- isArchived = isArchived,
- isAutoRun = isAutoRun,
- isAutoUpdate = isAutoUpdate,
- descriptorCreationTime = descriptorCreationTime,
- translationCreationTime = translationCreationTime,
- nettests = nettests ?: emptyList()
- )
- }
-}
diff --git a/app/src/main/res/layout/activity_add_descriptor.xml b/app/src/main/res/layout/activity_add_descriptor.xml
index 36fbf7298..73cd5198e 100644
--- a/app/src/main/res/layout/activity_add_descriptor.xml
+++ b/app/src/main/res/layout/activity_add_descriptor.xml
@@ -51,8 +51,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:resource="@{viewmodel.descriptor.icon}"
- tools:src="@drawable/settings_icon"
- app:color="@{viewmodel.color}" />
+ tools:src="@drawable/settings_icon" />
diff --git a/app/src/main/res/layout/activity_overview.xml b/app/src/main/res/layout/activity_overview.xml
index fd0140a75..cb192a83f 100644
--- a/app/src/main/res/layout/activity_overview.xml
+++ b/app/src/main/res/layout/activity_overview.xml
@@ -1,242 +1,219 @@
-
-
-
-
-
-
+
+
+
+
+ android:layout_marginTop="?attr/actionBarSize"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:paddingBottom="16dp"
+ app:layout_collapseMode="parallax">
+
+
-
-
+ android:layout_margin="8dp"
+ android:orientation="horizontal"
+ android:transitionName="@string/transitionNameRuntime">
+ android:orientation="vertical">
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
+ android:text="@string/Dashboard_Overview_LatestTest"
+ android:textColor="@android:color/white" />
-
-
+ android:layout_marginStart="16dp"
+ android:orientation="vertical">
+
+
+
+
+
-
+
+
+
+
-
-
+
+
-
+
+
+ android:layout_height="match_parent">
-
+ android:layout_height="wrap_content"
+ android:paddingHorizontal="16dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+
-
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dp"
+ android:layout_below="@+id/desc">
-
+ android:text="Install updates automatically" />
-
+
-
-
-
+
+
+
-
+
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ app:checkedState="indeterminate" />
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_review_descriptor_updates.xml b/app/src/main/res/layout/activity_review_descriptor_updates.xml
deleted file mode 100644
index 80fa5b690..000000000
--- a/app/src/main/res/layout/activity_review_descriptor_updates.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml
index aa4c63494..02de950e0 100644
--- a/app/src/main/res/layout/fragment_dashboard.xml
+++ b/app/src/main/res/layout/fragment_dashboard.xml
@@ -1,141 +1,132 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_descriptor_update.xml b/app/src/main/res/layout/fragment_descriptor_update.xml
deleted file mode 100644
index 651ad0184..000000000
--- a/app/src/main/res/layout/fragment_descriptor_update.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/add_descriptor.xml b/app/src/main/res/menu/add_descriptor.xml
index 632cc4035..ef6942339 100644
--- a/app/src/main/res/menu/add_descriptor.xml
+++ b/app/src/main/res/menu/add_descriptor.xml
@@ -1,10 +1,8 @@
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/update_descriptor.xml b/app/src/main/res/menu/update_descriptor.xml
deleted file mode 100644
index 5f4a92417..000000000
--- a/app/src/main/res/menu/update_descriptor.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index d263d6bb5..bde634449 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -20,7 +20,6 @@ androidxAppCompat = "1.6.1"
androidxConstraintlayout = "2.1.4"
androidxLifecycleProcess = "2.7.0"
androidxPreference = "1.2.1"
-workRuntime = "2.9.0"
androidxLocalbroadcastmanager = "1.1.0"
androidxLegacySupportV4 = "1.0.0"
androidxJunit = "1.1.5"
@@ -87,7 +86,6 @@ androidx-legacy-support-v4 = { module = "androidx.legacy:legacy-support-v4", ver
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-work-runtime = { module = "androidx.work:work-runtime", version.ref = "workRuntime" }
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" }