Skip to content

Commit

Permalink
Merge pull request #75 from infinum/develop
Browse files Browse the repository at this point in the history
Update Master with Release 1.4.0
  • Loading branch information
KCeh authored Jul 18, 2024
2 parents 87b5dae + cec47bc commit 164176a
Show file tree
Hide file tree
Showing 28 changed files with 306 additions and 132 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ Then add the following dependencies in your app `build.gradle` or `build.gradle.
**Groovy**

```groovy
def sentinelVersion = "1.3.3"
def sentinelVersion = "1.4.0"
debugImplementation "com.infinum.sentinel:sentinel:$sentinelVersion"
releaseImplementation "com.infinum.sentinel:sentinel-no-op:$sentinelVersion"
```

**KotlinDSL**

```kotlin
val sentinelVersion = "1.3.3"
val sentinelVersion = "1.4.0"
debugImplementation("com.infinum.sentinel:sentinel:$sentinelVersion")
releaseImplementation("com.infinum.sentinel:sentinel-no-op:$sentinelVersion")
```
Expand Down
4 changes: 2 additions & 2 deletions config.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ext {
def major = 1
def minor = 3
def patch = 3
def minor = 4
def patch = 0

buildConfig = [
"minSdk" : 21,
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
sentinel = "1.3.3"
sentinel = "1.4.0"
gradle = "8.3.2"
kotlin = "1.9.22"
coroutines = "1.8.0"
Expand Down
16 changes: 5 additions & 11 deletions sentinel/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@

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

<permission
android:name="com.infinum.sentinel.permission.ACCESS_SENTINEL"
android:protectionLevel="signature" />

<application>

<activity
android:name=".ui.main.SentinelActivity"
android:exported="true"
android:label="@string/sentinel_name"
android:permission="com.infinum.sentinel.permission.ACCESS_SENTINEL"
android:taskAffinity="com.infinum.sentinel"
android:theme="@style/Sentinel.Theme">
<meta-data
Expand Down Expand Up @@ -114,17 +119,6 @@
android:value="androidx.startup" />
</provider>

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>

</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ package com.infinum.sentinel.data.models.raw

internal data class PreferencesData(
val name: String,
val values: List<Triple<PreferenceType, String, Any>>
val values: List<Triple<PreferenceType, String, Any>>,
val isSortedAscending: Boolean = false,
val isExpanded: Boolean = true,
)
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ internal class PreferencesCollector(
prefsDirectory.list().orEmpty().toList().map { it.removeSuffix(PREFS_SUFFIX) }
} else {
listOf()
}.sortedBy { name ->
name
}.map { name ->
val allPrefs = getSharedPreferences(name, MODE_PRIVATE).all
val tuples = allPrefs.keys.toSet().mapNotNull {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ internal object LibraryComponents {
tools.filterIsInstance<CertificateTool>().firstOrNull()?.userCertificates.orEmpty(),
onTriggered
)
WorkManagerInitializer.init(domainComponent)
domainComponent.setup()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.infinum.sentinel.di

import com.infinum.sentinel.di.component.DomainComponent
import com.infinum.sentinel.ui.certificates.observer.CertificateCheckWorker
import com.infinum.sentinel.ui.certificates.observer.DelegateWorker
import com.infinum.sentinel.ui.certificates.observer.SentinelWorkerFactory

internal object WorkManagerInitializer {

fun init(domainComponent: DomainComponent) {
DelegateWorker.workerFactories[CertificateCheckWorker.NAME] =
SentinelWorkerFactory(domainComponent.collectors, domainComponent.notificationFactory)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import com.infinum.sentinel.ui.bundles.callbacks.BundleMonitorNotificationCallba
import com.infinum.sentinel.ui.bundles.details.BundleDetailsActivity
import com.infinum.sentinel.ui.certificates.observer.CertificatesObserver
import com.infinum.sentinel.ui.certificates.observer.SentinelWorkManager
import com.infinum.sentinel.ui.certificates.observer.SentinelWorkerFactory
import com.infinum.sentinel.ui.crash.anr.SentinelAnrObserver
import com.infinum.sentinel.ui.crash.anr.SentinelAnrObserverRunnable
import com.infinum.sentinel.ui.crash.anr.SentinelUiAnrObserver
Expand Down Expand Up @@ -91,8 +90,6 @@ internal abstract class DomainComponent(

abstract val sentinelAnrObserver: SentinelAnrObserver

abstract val sentinelWorkerFactory: SentinelWorkerFactory

abstract val sentinelWorkManager: SentinelWorkManager

abstract val sentinelAnrObserverRunnable: SentinelAnrObserverRunnable
Expand Down Expand Up @@ -157,15 +154,10 @@ internal abstract class DomainComponent(
fun sentinelAnrObserverRunnable(dao: CrashesDao): SentinelAnrObserverRunnable =
SentinelAnrObserverRunnable(context, notificationFactory, dao)

@Provides
@DomainScope
fun sentinelWorkerFactory(): SentinelWorkerFactory =
SentinelWorkerFactory(collectors, notificationFactory)

@Provides
@DomainScope
fun sentinelWorkManager(): SentinelWorkManager =
SentinelWorkManager(context, sentinelWorkerFactory)
SentinelWorkManager(context)

@Provides
@DomainScope
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.infinum.sentinel.ui.certificates.observer

import android.content.Context
import androidx.annotation.UiThread
import androidx.work.ListenableWorker
import androidx.work.WorkerFactory
import androidx.work.WorkerParameters
import com.google.common.util.concurrent.ListenableFuture
import com.infinum.sentinel.ui.shared.Constants.Keys.WORKER_CLASS_NAME
import com.infinum.sentinel.ui.shared.Constants.Keys.WORKER_ID

/**
* A worker to delegate work requests from within the library to workers
* that require factories with custom dependencies.
*/
internal class DelegateWorker(
appContext: Context,
parameters: WorkerParameters,
) : ListenableWorker(appContext, parameters) {

private val workerClassName =
parameters.inputData.getString(WORKER_CLASS_NAME) ?: ""
private val workerId = parameters.inputData.getString(WORKER_ID)
private val delegateWorkerFactory = workerFactories[workerId]
private val delegatedWorker = delegateWorkerFactory?.createWorker(appContext, workerClassName, parameters)

override fun startWork(): ListenableFuture<Result> {
return if (delegatedWorker != null) {
delegatedWorker.startWork()
} else {
val errorMessage = "No delegateWorker available for $workerId" +
" with workerClassName of $workerClassName. Is the " +
"DelegateWorker.workerFactories populated correctly?"
throw IllegalStateException(errorMessage)
}
}

companion object {
const val DELEGATE_WORKER_ID = "com.infinum.sentinel.ui.certificates.observer.CertificateCheckWorker"

val workerFactories = object : AbstractMutableMap<String, WorkerFactory>() {

private val backingWorkerMap = mutableMapOf<String, WorkerFactory>()

@UiThread
override fun put(key: String, value: WorkerFactory): WorkerFactory? {
return backingWorkerMap.put(key, value)
}

override val entries: MutableSet<MutableMap.MutableEntry<String, WorkerFactory>>
get() = backingWorkerMap.entries
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ import android.content.Context
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.asFlow
import androidx.work.Configuration
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.WorkManager
import androidx.work.WorkerFactory
import androidx.work.workDataOf
import com.infinum.sentinel.BuildConfig
import com.infinum.sentinel.data.models.local.CertificateMonitorEntity
import com.infinum.sentinel.ui.shared.Constants.Keys.EXPIRE_IN_AMOUNT
import com.infinum.sentinel.ui.shared.Constants.Keys.EXPIRE_IN_UNIT
import com.infinum.sentinel.ui.shared.Constants.Keys.NOTIFY_INVALID_NOW
import com.infinum.sentinel.ui.shared.Constants.Keys.NOTIFY_TO_EXPIRE
import com.infinum.sentinel.ui.shared.Constants.Keys.WORKER_CLASS_NAME
import com.infinum.sentinel.ui.shared.Constants.Keys.WORKER_ID
import java.time.Duration
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
Expand All @@ -28,44 +28,34 @@ import me.tatarka.inject.annotations.Inject
@Inject
internal class SentinelWorkManager(
private val context: Context,
private val workerFactory: WorkerFactory
) {

companion object {
private const val DEBUG_INTERVAL = 15L
private const val RELEASE_INTERVAL = 1440L
}

init {
WorkManager.initialize(
context,
Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.INFO)
.setWorkerFactory(workerFactory)
.build()
)
}

@RequiresApi(Build.VERSION_CODES.O)
fun startCertificatesCheck(entity: CertificateMonitorEntity) =
fun startCertificatesCheck(entity: CertificateMonitorEntity) {

val delegatedWorkData = workDataOf(
WORKER_CLASS_NAME to CertificateCheckWorker::class.qualifiedName,
WORKER_ID to CertificateCheckWorker.NAME,
NOTIFY_INVALID_NOW to entity.notifyInvalidNow,
NOTIFY_TO_EXPIRE to entity.notifyToExpire,
EXPIRE_IN_AMOUNT to entity.expireInAmount,
EXPIRE_IN_UNIT to entity.expireInUnit.name
)
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
CertificateCheckWorker.NAME,
DelegateWorker.DELEGATE_WORKER_ID,
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
PeriodicWorkRequestBuilder<CertificateCheckWorker>(
PeriodicWorkRequestBuilder<DelegateWorker>(
when (BuildConfig.DEBUG) {
true -> Duration.ofMinutes(DEBUG_INTERVAL)
false -> Duration.ofMinutes(RELEASE_INTERVAL)
}
)
.setInputData(
workDataOf(
NOTIFY_INVALID_NOW to entity.notifyInvalidNow,
NOTIFY_TO_EXPIRE to entity.notifyToExpire,
EXPIRE_IN_AMOUNT to entity.expireInAmount,
EXPIRE_IN_UNIT to entity.expireInUnit.name
)
)
).setInputData(delegatedWorkData)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
Expand All @@ -80,6 +70,7 @@ internal class SentinelWorkManager(
)
.build()
)
}

fun certificatesCheckState(): Flow<Boolean> =
WorkManager.getInstance(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,32 +64,51 @@ internal class PreferencesFragment :
}
}

@Suppress("UNCHECKED_CAST")
private fun createItemView(data: PreferencesData): View =
SentinelViewItemPreferenceBinding.inflate(layoutInflater, binding.contentLayout, false)
.apply {
nameView.text = data.name
data.values.forEach { tuple ->
prefsLayout.addView(
SentinelViewItemTextBinding.inflate(layoutInflater, prefsLayout, false)
.apply {
labelView.isAllCaps = false
labelView.text = tuple.second
valueView.text = tuple.third.toString()
root.setOnClickListener { _ ->
viewModel.cache(
data.name,
tuple
)
}
root.setOnLongClickListener {
it.context.copyToClipboard(
key = tuple.second,
value = tuple.third.toString()
)
}
}.root
)
sortImageView.setOnClickListener {
viewModel.onSortClicked(data)
}
hideExpandImageView.setOnClickListener {
viewModel.onHideExpandClicked(data)
}

if (data.isExpanded) {
prefsLayout.visibility = View.VISIBLE
sortImageView.visibility = View.VISIBLE
hideExpandImageView.setImageResource(R.drawable.sentinel_ic_minus)
showPreferenceData(data)
} else {
prefsLayout.visibility = View.GONE
sortImageView.visibility = View.GONE
hideExpandImageView.setImageResource(R.drawable.sentinel_ic_plus)
}
}.root

private fun SentinelViewItemPreferenceBinding.showPreferenceData(data: PreferencesData) {
data.values.forEach { (preferenceType, label, value) ->
prefsLayout.addView(
SentinelViewItemTextBinding.inflate(layoutInflater, prefsLayout, false)
.apply {
labelView.isAllCaps = false
labelView.text = label
valueView.text = value.toString()
root.setOnClickListener { _ ->
viewModel.cache(
name = data.name,
tuple = Triple(preferenceType, label, value)
)
}
root.setOnLongClickListener {
it.context.copyToClipboard(
key = label,
value = value.toString()
)
}
}.root
)
}
}
}
Loading

0 comments on commit 164176a

Please sign in to comment.