Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Expansion of Preferences Manager #96

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SampleApplication : Application() {
override fun onCreate() {
super.onCreate()

Sentinel.watch(getWatchedTools())
Sentinel.watch(getWatchedTools(), mapOf("ENCRYPTED_SHARED_PREFERENCES" to emptyList()))
}

private fun getWatchedTools(): Set<Sentinel.Tool> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import com.infinum.sentinel.ui.main.SentinelFragment
import com.infinum.sentinel.ui.main.application.ApplicationFragment
import com.infinum.sentinel.ui.main.device.DeviceFragment
import com.infinum.sentinel.ui.main.permissions.PermissionsFragment
import com.infinum.sentinel.ui.main.preferences.PreferencesFragment
import com.infinum.sentinel.ui.main.preferences.targeted.TargetedPreferencesFragment
import com.infinum.sentinel.ui.main.tools.ToolsFragment
import com.infinum.sentinel.ui.settings.SettingsActivity
import com.infinum.sentinel.ui.settings.SettingsFragment
Expand Down Expand Up @@ -223,7 +223,7 @@ public class SentinelFragmentTests {
).perform(lenientClick())

scenario.onFragment {
val childFragment = it.childFragmentManager.findFragmentByTag(PreferencesFragment.TAG)
val childFragment = it.childFragmentManager.findFragmentByTag(TargetedPreferencesFragment.TAG)

assertNotNull(childFragment)
}
Expand Down
23 changes: 12 additions & 11 deletions sentinel/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

<application>

Expand All @@ -13,7 +13,7 @@
android:theme="@style/Sentinel.Theme">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>

<activity
Expand All @@ -24,7 +24,7 @@
android:theme="@style/Sentinel.Theme.Leaf">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>

<activity
Expand All @@ -35,7 +35,7 @@
android:theme="@style/Sentinel.Theme.Leaf">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>

<activity
Expand All @@ -46,7 +46,7 @@
android:theme="@style/Sentinel.Theme.Leaf">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>

<activity
Expand All @@ -57,7 +57,7 @@
android:theme="@style/Sentinel.Theme.Leaf">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>

<activity
Expand All @@ -68,7 +68,7 @@
android:theme="@style/Sentinel.Theme.Leaf">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>

<activity
Expand All @@ -79,7 +79,7 @@
android:theme="@style/Sentinel.Theme.Leaf">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>

<activity
Expand All @@ -91,7 +91,7 @@
tools:targetApi="o">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>

<activity
Expand All @@ -103,8 +103,9 @@
tools:targetApi="o">
<meta-data
android:name="@string/sentinel_infinum_monitored"
android:value="false" />
android:value="false"/>
</activity>
<activity android:name="com.infinum.sentinel.ui.main.preferences.all.AllPreferencesActivity"/>

<provider
android:name="androidx.startup.InitializationProvider"
Expand All @@ -113,7 +114,7 @@
tools:node="merge">
<meta-data
android:name="com.infinum.sentinel.SentinelInitializer"
android:value="androidx.startup" />
android:value="androidx.startup"/>
</provider>

</application>
Expand Down
24 changes: 22 additions & 2 deletions sentinel/src/main/kotlin/com/infinum/sentinel/Sentinel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,30 @@ import java.util.Locale

public object Sentinel {

/**
* Used to initialize Sentinel.
*
* @param tools list of tools you want to have e.g. ChuckerTool
* @param targetedPreferences map of preference files and their properties, used to make finding specific
* properties more easily, if properties list is empty returns all properties of that file
*
* **Example:**
* // This will contain only tools which are default to Sentinel
* Sentinel.watch()
*
* // This will contain default Sentinel tools + Chucker
* Sentinel.watch(setOf(ChuckerTool()))
*
* // This will contain default Sentinel tools + Chucker and all preference properties of MY_PREFS_FILE
* Sentinel.watch(setOf(ChuckerTool()), mapOf("MY_PREFS_FILE" to emptyList()))
*
* // This will contain default Sentinel tools + Chucker and only MY_PROPERTY property of MY_PREFS_FILE
* Sentinel.watch(setOf(ChuckerTool()), mapOf("MY_PREFS_FILE" to listOf("MY_PROPERTY")))
*/
Comment on lines +16 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kudos for docs 👏

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have questions:

  1. I know this might counter your design goal (selected prefs and all prefs on separate screens). But, can you watch all preferences in this selected preferences quick view? How? Regardless of answer could we add an example in docs to watch 2 separate files?
  2. How does the iOS version behave in the default state where a user of lib doesn't specify which preferences they want to watch

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this might counter your design goal (selected prefs and all prefs on separate screens). But, can you watch all preferences in this selected preferences quick view? How? Regardless of answer could we add an example in docs to watch 2 separate files?

In selected preferences quick view, you can monitor multiple files but you have to provide names of those files. If that's what you are asking. IMO, it makes sense since app will have dozens of not so relevant files which are then cluttering your UI [but you can access them in AllFiles].

How does the iOS version behave in the default state where a user of lib doesn't specify which preferences they want to watch

To my knowledge, they don't have option to display all files, they just display what clients want. They also have some logic of mapping where clients can provide readable names of properties (instead of KEY_ONE they can send mapping "key one" which is more readable lets say.) I will have to double check with them just in case.

@JvmStatic
@JvmOverloads
public fun watch(tools: Set<Tool> = setOf()): Sentinel {
LibraryComponents.setup(tools) { LibraryComponents.presentation().show() }
public fun watch(tools: Set<Tool> = setOf(), targetedPreferences: Map<String, List<String>> = mapOf()): Sentinel {
LibraryComponents.setup(tools, targetedPreferences) { LibraryComponents.presentation().show() }
return this
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.infinum.sentinel.data.sources.raw.collectors

import android.content.Context
import android.content.Context.MODE_PRIVATE
import com.infinum.sentinel.data.models.raw.PreferenceType
import com.infinum.sentinel.data.models.raw.PreferencesData
import com.infinum.sentinel.domain.collectors.Collectors
import me.tatarka.inject.annotations.Inject

@Inject
internal class TargetedPreferencesCollector(
private val context: Context,
private val targetedPreferences: Map<String, List<String>>
) : Collectors.TargetedPreferences {

override fun invoke(): List<PreferencesData> {
if (targetedPreferences.isEmpty()) return emptyList()

return targetedPreferences.mapNotNull { (fileName, keys) ->
val allPrefs = context.getSharedPreferences(fileName, MODE_PRIVATE).all

val tuples = allPrefs.keys
.filter { keys.isEmpty() || keys.contains(it) }
.mapNotNull { key ->
@Suppress("UNCHECKED_CAST")
when (val value = allPrefs[key]) {
is Boolean -> Triple(PreferenceType.BOOLEAN, key, value)
is Float -> Triple(PreferenceType.FLOAT, key, value)
is Int -> Triple(PreferenceType.INT, key, value)
is Long -> Triple(PreferenceType.LONG, key, value)
is String -> Triple(PreferenceType.STRING, key, value)
is Set<*> -> Triple(PreferenceType.SET, key, value as Set<String>)
else -> null
}
}

if (tuples.isNotEmpty()) PreferencesData(fileName, tuples) else null
Comment on lines +11 to +37
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be included in regular PreferencesCollector?
As far as I see only difference is using targetedPreferences as source. We could use targetedPreferences as parameter
Correct me if I am wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it can be done. I would just have to add additional filtering of files since there we also fetch all preference files. 👍

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ internal object LibraryComponents {
presentationComponent = PresentationComponent::class.create(context, viewModelComponent)
}

fun setup(tools: Set<Sentinel.Tool>, onTriggered: () -> Unit) {
fun setup(tools: Set<Sentinel.Tool>, targetedPreferences: Map<String, List<String>>, onTriggered: () -> Unit) {
dataComponent.setup(
tools.plus(DEFAULT_TOOLS),
targetedPreferences,
tools.filterIsInstance<CertificateTool>().firstOrNull()?.userCertificates.orEmpty(),
onTriggered
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.infinum.sentinel.data.sources.raw.collectors.CertificateCollector
import com.infinum.sentinel.data.sources.raw.collectors.DeviceCollector
import com.infinum.sentinel.data.sources.raw.collectors.PermissionsCollector
import com.infinum.sentinel.data.sources.raw.collectors.PreferencesCollector
import com.infinum.sentinel.data.sources.raw.collectors.TargetedPreferencesCollector
import com.infinum.sentinel.data.sources.raw.collectors.ToolsCollector
import com.infinum.sentinel.data.sources.raw.formatters.HtmlFormatter
import com.infinum.sentinel.data.sources.raw.formatters.JsonFormatter
Expand All @@ -54,15 +55,18 @@ internal abstract class DataComponent(
private val context: Context
) {
private var tools: Set<Sentinel.Tool> = setOf()
private var targetedPreferences: Map<String, List<String>> = mapOf()
private var userCertificates: List<X509Certificate> = listOf()
private var onTriggered: () -> Unit = {}

fun setup(
tools: Set<Sentinel.Tool>,
targetedPreferences: Map<String, List<String>>,
userCertificates: List<X509Certificate>,
onTriggered: () -> Unit
) {
this.tools = tools
this.targetedPreferences = targetedPreferences
this.userCertificates = userCertificates
this.onTriggered = onTriggered
}
Expand Down Expand Up @@ -151,6 +155,8 @@ internal abstract class DataComponent(

abstract val preferencesCollector: Collectors.Preferences

abstract val targetedPreferencesCollector: Collectors.TargetedPreferences

abstract val certificatesCollector: Collectors.Certificates

abstract val toolsCollector: Collectors.Tools
Expand Down Expand Up @@ -185,6 +191,11 @@ internal abstract class DataComponent(
fun preferencesCollector(): Collectors.Preferences =
PreferencesCollector(context)

@Provides
@DataScope
fun targetedPreferencesCollector(): Collectors.TargetedPreferences =
TargetedPreferencesCollector(context, targetedPreferences)

@Provides
@DataScope
fun certificatesCollector(): Collectors.Certificates =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,11 @@ internal abstract class DomainComponent(
application: Collectors.Application,
permissions: Collectors.Permissions,
preferences: Collectors.Preferences,
targetedPreferences: Collectors.TargetedPreferences,
certificates: Collectors.Certificates,
tools: Collectors.Tools
): Factories.Collector =
CollectorFactory(device, application, permissions, preferences, certificates, tools)
CollectorFactory(device, application, permissions, preferences, targetedPreferences, certificates, tools)

@Provides
@DomainScope
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import com.infinum.sentinel.ui.main.SentinelViewModel
import com.infinum.sentinel.ui.main.application.ApplicationViewModel
import com.infinum.sentinel.ui.main.device.DeviceViewModel
import com.infinum.sentinel.ui.main.permissions.PermissionsViewModel
import com.infinum.sentinel.ui.main.preferences.PreferencesViewModel
import com.infinum.sentinel.ui.main.preferences.all.AllPreferencesViewModel
import com.infinum.sentinel.ui.main.preferences.editor.PreferenceEditorViewModel
import com.infinum.sentinel.ui.main.preferences.targeted.TargetedPreferencesViewModel
import com.infinum.sentinel.ui.main.tools.ToolsViewModel
import com.infinum.sentinel.ui.settings.SettingsViewModel
import me.tatarka.inject.annotations.Component
Expand All @@ -35,7 +36,9 @@ internal abstract class ViewModelComponent(

abstract val permissions: PermissionsViewModel

abstract val preferences: PreferencesViewModel
abstract val allPreferences: AllPreferencesViewModel

abstract val targetedPreferences: TargetedPreferencesViewModel

abstract val preferenceEditor: PreferenceEditorViewModel

Expand Down Expand Up @@ -77,8 +80,13 @@ internal abstract class ViewModelComponent(

@IntoMap
@Provides
fun preferences(): Pair<Class<*>, ViewModel> =
PreferencesViewModel::class.java to preferences
fun allPreferences(): Pair<Class<*>, ViewModel> =
AllPreferencesViewModel::class.java to allPreferences

@IntoMap
@Provides
fun targetedPreferences(): Pair<Class<*>, ViewModel> =
TargetedPreferencesViewModel::class.java to targetedPreferences

@IntoMap
@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ internal interface Factories {

fun preferences(): Collectors.Preferences

fun targetedPreferences(): Collectors.TargetedPreferences

fun certificates(): Collectors.Certificates

fun tools(): Collectors.Tools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package com.infinum.sentinel.domain.collectors

import com.infinum.sentinel.domain.Factories

@Suppress("LongParameterList")
internal class CollectorFactory(
private val device: Collectors.Device,
private val application: Collectors.Application,
private val permissions: Collectors.Permissions,
private val preferences: Collectors.Preferences,
private val targetedPreferences: Collectors.TargetedPreferences,
private val certificates: Collectors.Certificates,
private val tools: Collectors.Tools
) : Factories.Collector {
Expand All @@ -19,6 +21,8 @@ internal class CollectorFactory(

override fun preferences(): Collectors.Preferences = preferences

override fun targetedPreferences(): Collectors.TargetedPreferences = targetedPreferences

override fun certificates(): Collectors.Certificates = certificates

override fun tools(): Collectors.Tools = tools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ internal interface Collectors {

interface Preferences : Collector<List<PreferencesData>>

interface TargetedPreferences : Collector<List<PreferencesData>>

interface Certificates : Collector<Map<CertificateType, List<CertificateData>>>

interface Tools : Collector<Set<Sentinel.Tool>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.infinum.sentinel.extensions.viewModels
import com.infinum.sentinel.ui.main.application.ApplicationFragment
import com.infinum.sentinel.ui.main.device.DeviceFragment
import com.infinum.sentinel.ui.main.permissions.PermissionsFragment
import com.infinum.sentinel.ui.main.preferences.PreferencesFragment
import com.infinum.sentinel.ui.main.preferences.targeted.TargetedPreferencesFragment
import com.infinum.sentinel.ui.main.tools.ToolsFragment
import com.infinum.sentinel.ui.settings.SettingsActivity
import com.infinum.sentinel.ui.shared.base.BaseFragment
Expand Down Expand Up @@ -101,7 +101,7 @@ internal class SentinelFragment :
R.id.device -> showFragment(DeviceFragment.TAG)
R.id.application -> showFragment(ApplicationFragment.TAG)
R.id.permissions -> showFragment(PermissionsFragment.TAG)
R.id.preferences -> showFragment(PreferencesFragment.TAG)
R.id.preferences -> showFragment(TargetedPreferencesFragment.TAG)
}
true
}
Expand All @@ -124,7 +124,7 @@ internal class SentinelFragment :
DeviceFragment.TAG -> DeviceFragment.newInstance()
ApplicationFragment.TAG -> ApplicationFragment.newInstance()
PermissionsFragment.TAG -> PermissionsFragment.newInstance()
PreferencesFragment.TAG -> PreferencesFragment.newInstance()
TargetedPreferencesFragment.TAG -> TargetedPreferencesFragment.newInstance()
ToolsFragment.TAG -> ToolsFragment.newInstance()
else -> null
}?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import com.infinum.sentinel.ui.shared.delegates.viewBinding

@RestrictTo(RestrictTo.Scope.LIBRARY)
internal class PermissionsFragment :
BaseChildFragment<PermissionsState, Nothing>(R.layout.sentinel_fragment_preferences) {
BaseChildFragment<PermissionsState, Nothing>(R.layout.sentinel_fragment_all_preferences) {

companion object {
fun newInstance() = PermissionsFragment()
Expand Down

This file was deleted.

Loading
Loading