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

Release 1.3.2 #57

Merged
merged 33 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8109d2a
Add remember active state of sensor trigger
KCeh Feb 13, 2024
247642a
Update cache when saving Trigger DAO
KCeh Feb 13, 2024
8a5f749
Fix lint
KCeh Feb 13, 2024
09879ea
Update code-analysis.yml
KCeh Feb 13, 2024
f8b0119
Add Android 13 notification permission support
KCeh Feb 13, 2024
6ab47f3
Add notification permission check
KCeh Feb 13, 2024
e7a31aa
Extract string resources
KCeh Feb 13, 2024
995781d
Use package schema string in UI tool
KCeh Feb 14, 2024
7d1113e
Add notifications permission check for certificates
KCeh Feb 14, 2024
ed0f9a8
Merge pull request #49 from infinum/fix/github-action-for-code-analysis
KCeh Mar 1, 2024
23ebca4
Merge branch 'develop' into fix/trigger-init-not-working-properly-on-…
KCeh Mar 1, 2024
93513de
Update code-analysis.yml
KCeh Mar 1, 2024
0cba734
Merge pull request #51 from infinum/fix/CI-jobs-Java17
KCeh Mar 1, 2024
3d81cd7
Merge branch 'develop' into fix/crash-notifications-not-showing-on-an…
KCeh Mar 1, 2024
4464222
Merge branch 'develop' into fix/trigger-init-not-working-properly-on-…
KCeh Mar 1, 2024
347e0bc
Fix detekt
KCeh Mar 1, 2024
1094244
Merge branch 'fix/crash-notifications-not-showing-on-android-13' of h…
KCeh Mar 1, 2024
6f20c95
Merge pull request #50 from infinum/fix/crash-notifications-not-showi…
KCeh Mar 4, 2024
3d28a7e
Merge branch 'develop' into fix/trigger-init-not-working-properly-on-…
KCeh Mar 4, 2024
dd1d5dd
Add don't obfuscate rule
KCeh Mar 6, 2024
4dbbe12
Remove sensor trigger
KCeh Mar 6, 2024
42d34f6
Bump version
KCeh Mar 6, 2024
423a0f9
Merge pull request #54 from infinum/bump-version-to-1.3.2
KCeh Mar 6, 2024
a9d786f
Merge branch 'develop' into feature/disable-obfuscation
KCeh Mar 6, 2024
c0eee7b
Merge branch 'develop' into fix/trigger-init-not-working-properly-on-…
KCeh Mar 6, 2024
4b5123a
Merge pull request #53 from infinum/feature/disable-obfuscation
KCeh Mar 6, 2024
d4741a6
Merge branch 'develop' into fix/trigger-init-not-working-properly-on-…
KCeh Mar 6, 2024
6877def
Merge pull request #48 from infinum/fix/trigger-init-not-working-prop…
KCeh Mar 6, 2024
1649718
Bump sentinel version
KCeh Mar 6, 2024
ad427b6
Merge pull request #55 from infinum/bump-version-in-version-catalog
KCeh Mar 6, 2024
eec30b7
Revert "Merge branch 'develop' into fix/trigger-init-not-working-prop…
KCeh Mar 6, 2024
aea966f
Merge pull request #56 from infinum/fix/revert-obfuscations
KCeh Mar 6, 2024
86bcd90
Merge branch 'master' into develop
KCeh Mar 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ _Plain_ formatter is selected by default, but selecting any other is persisted b
## Crash monitor

_Sentinel_ has a built in default uncaught exception handler and ANR observer. If switched on in
settings, it will notify both in a form of a notification.
settings, it will notify both in a form of a notification. Note that from Android 13 you need to give permission
to the app to show notifications.
Once tapped on this notification, a screen with details is shown. A complete list of crashes is
persisted between sessions and available on demand.
Methods to react on these crashes in a graceful way are provided in _Sentinel_.
Expand Down
2 changes: 1 addition & 1 deletion 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 = 1
def patch = 2

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.1"
sentinel = "1.3.2"
gradle = "8.0.2"
desugar = "2.0.3"
kotlin = "1.8.21"
Expand Down
2 changes: 2 additions & 0 deletions sentinel/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<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" />

<application>

<activity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ internal abstract class SensorTrigger(
sensorManager = (context.getSystemService(Context.SENSOR_SERVICE) as? SensorManager)
sensorManager?.let {
registerSensor(it)
this.active = true
} ?: run {
this.active = false
}
Expand All @@ -34,7 +33,6 @@ internal abstract class SensorTrigger(
queue?.clear()
unregisterSensor()
sensorManager = null
this.active = false
}

override fun onSensorChanged(event: SensorEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal class TriggersRepository(
override suspend fun save(input: TriggerParameters) =
input.entity?.let {
dao.save(it)
updateCache(it)
} ?: error("Cannot save null entity")

override fun load(input: TriggerParameters): Flow<List<TriggerEntity>> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ internal sealed class SettingsEvent {
data class CertificateMonitorChanged(
val value: CertificateMonitorEntity
) : SettingsEvent()

object PermissionsCheck : SettingsEvent()
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package com.infinum.sentinel.ui.settings

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RestrictTo
import androidx.core.content.ContextCompat
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.switchmaterial.SwitchMaterial
import com.infinum.sentinel.R
import com.infinum.sentinel.data.models.local.FormatEntity
Expand Down Expand Up @@ -33,6 +43,18 @@ internal class SettingsFragment : BaseChildFragment<Nothing, SettingsEvent>(R.la

override val viewModel: SettingsViewModel by viewModels()

private val permissionRequest = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isPermissionGranted: Boolean ->
if (!isPermissionGranted) {
Toast.makeText(
requireContext(),
getString(R.string.sentinel_notification_permission_denied),
Toast.LENGTH_LONG,
).show()
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

Expand Down Expand Up @@ -107,10 +129,12 @@ internal class SettingsFragment : BaseChildFragment<Nothing, SettingsEvent>(R.la
binding.airplaneModeTriggerView,
trigger
)

else -> throw NotImplementedError()
}
}
}

is SettingsEvent.FormatChanged -> {
when (event.value.type) {
FormatType.PLAIN -> R.id.plainChip
Expand All @@ -123,6 +147,7 @@ internal class SettingsFragment : BaseChildFragment<Nothing, SettingsEvent>(R.la
binding.formatGroup.check(it)
}
}

is SettingsEvent.BundleMonitorChanged -> {
binding.bundleMonitorSwitch.setOnCheckedChangeListener(null)
binding.bundleMonitorSwitch.isChecked = event.value.notify
Expand Down Expand Up @@ -167,6 +192,7 @@ internal class SettingsFragment : BaseChildFragment<Nothing, SettingsEvent>(R.la
}
binding.limitValueView.text = String.format(FORMAT_BUNDLE_SIZE, event.value.limit)
}

is SettingsEvent.CrashMonitorChanged -> {
binding.uncaughtExceptionSwitch.setOnCheckedChangeListener(null)
binding.uncaughtExceptionSwitch.isChecked = event.value.notifyExceptions
Expand All @@ -184,6 +210,7 @@ internal class SettingsFragment : BaseChildFragment<Nothing, SettingsEvent>(R.la
viewModel.updateCrashMonitor(event.value.copy(includeAllData = isChecked))
}
}

is SettingsEvent.CertificateMonitorChanged -> {
binding.runOnStartSwitch.setOnCheckedChangeListener(null)
binding.runOnStartSwitch.isChecked = event.value.runOnStart
Expand Down Expand Up @@ -240,8 +267,48 @@ internal class SettingsFragment : BaseChildFragment<Nothing, SettingsEvent>(R.la
viewModel.updateCertificatesMonitor(event.value.copy(expireInUnit = ChronoUnit.YEARS))
}
}

SettingsEvent.PermissionsCheck -> {
handleNotificationsPermission()
}
}

private fun handleNotificationsPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
return
}
when {
ContextCompat.checkSelfPermission(
requireContext(), Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED -> {
// We have permission, all good
}

shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> {
Snackbar.make(
binding.root,
getString(R.string.sentinel_notification_permission_denied),
Snackbar.LENGTH_LONG
).setAction(getString(R.string.sentinel_change)) {
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
data = Uri.fromParts(
getString(R.string.sentinel_package_schema),
requireContext().packageName,
null
)
}.also { intent ->
startActivity(intent)
}
}.show()
}

else -> {
permissionRequest.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
}

private fun setupSwitch(switchView: SwitchMaterial, trigger: TriggerEntity) =
with(switchView) {
setOnCheckedChangeListener(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,14 @@ internal class SettingsViewModel(
anrObserver.stop()
}
}
if (isAtLeastSomeCrashOptionChecked(entity)) {
emitEvent(SettingsEvent.PermissionsCheck)
}
}

private fun isAtLeastSomeCrashOptionChecked(entity: CrashMonitorEntity): Boolean =
entity.notifyAnrs || entity.notifyExceptions

fun updateCertificatesMonitor(entity: CertificateMonitorEntity) {
launch {
io {
Expand All @@ -141,6 +147,12 @@ internal class SettingsViewModel(
workManager.startCertificatesCheck(it)
} ?: workManager.stopCertificatesCheck()
}
if (isAtLeastSomeCertificateOptionChecked(entity)) {
emitEvent(SettingsEvent.PermissionsCheck)
}
}
}

private fun isAtLeastSomeCertificateOptionChecked(entity: CertificateMonitorEntity): Boolean =
entity.runOnStart || entity.runInBackground || entity.notifyInvalidNow || entity.notifyToExpire
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.infinum.sentinel.data.models.local.CrashEntity
import com.infinum.sentinel.ui.shared.Constants.NOTIFICATIONS_CHANNEL_ID
import me.tatarka.inject.annotations.Inject

@Suppress("TooManyFunctions")
@Inject
internal class SystemNotificationFactory(
private val context: Context,
Expand All @@ -29,6 +30,14 @@ internal class SystemNotificationFactory(
private val notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

private fun canShowNotifications(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
notificationManager.areNotificationsEnabled()
} else {
true
}
}

init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(
Expand Down Expand Up @@ -117,6 +126,9 @@ internal class SystemNotificationFactory(
content: String,
intents: Array<Intent>,
) {
if (!canShowNotifications()) {
return
}
val builder = NotificationCompat.Builder(context, NOTIFICATIONS_CHANNEL_ID)
.setContentIntent(buildPendingIntent(intents))
.setLocalOnly(true)
Expand All @@ -139,6 +151,7 @@ internal class SystemNotificationFactory(
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ->
PendingIntent.FLAG_MUTABLE

else -> PendingIntent.FLAG_CANCEL_CURRENT
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ internal data class AppInfoTool(
it.context.startActivity(
Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts(SCHEME_PACKAGE, it.context.packageName, null)
data = Uri.fromParts(
it.context.getString(R.string.sentinel_package_schema),
it.context.packageName,
null
)
}
)
}
) : Sentinel.Tool {

companion object {
private const val SCHEME_PACKAGE = "package"
}

/**
* A dedicated name for this tool
*
Expand Down
5 changes: 5 additions & 0 deletions sentinel/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<string name="sentinel_search">Search</string>
<string name="sentinel_show">Show</string>
<string name="sentinel_save">Save</string>
<string name="sentinel_change">Change</string>

<string name="sentinel_network">Network</string>
<string name="sentinel_memory">Memory</string>
Expand Down Expand Up @@ -151,5 +152,9 @@
<string name="sentinel_months">Months</string>
<string name="sentinel_years">Years</string>

<string name="sentinel_notification_permission_denied">Notification permission denied. Can\'t show info</string>

<string name="sentinel_unknown">unknown</string>
<string name="sentinel_package_schema">package</string>

</resources>
12 changes: 12 additions & 0 deletions sentinel/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
<item name="colorOnSurfaceInverse">@color/sentinel_inverseOnSurface</item>
<item name="colorSurfaceInverse">@color/sentinel_inverseSurface</item>
<item name="colorPrimaryInverse">@color/sentinel_primaryInverse</item>
<item name="snackbarStyle">@style/Sentinel.Snackbar</item>
<item name="snackbarButtonStyle">@style/Sentinel.Snackbar.TextButton</item>
</style>

<style name="Sentinel.Theme" parent="Sentinel.BaseTheme">
Expand Down Expand Up @@ -89,4 +91,14 @@
<style name="Sentinel.Animation" parent="@android:style/Animation">
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
</style>

<style name="Sentinel.Snackbar" parent="@style/Widget.MaterialComponents.Snackbar">
<item name="android:background">@color/sentinel_onBackground</item>
</style>

<style name="Sentinel.Snackbar.TextButton" parent="@style/Widget.MaterialComponents.Button.TextButton.Snackbar">
<item name="android:textColor">@color/sentinel_primary</item>
</style>


</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class LoggerActivity : AppCompatActivity() {
}
)

@Suppress("LongMethod", "CyclomaticComplexMethod")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ internal class LoggerAdapter(
currentList: MutableList<SentinelFileTree.Entry>
) =
onListChanged(currentList.isEmpty())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ internal class LoggerViewHolder(
stackTraceContainer.isVisible = false
root.setOnClickListener(null)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ internal class LogsAdapter(
currentList: MutableList<File>
) =
onListChanged(currentList.isEmpty())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ internal class LogsViewHolder(
deleteButton.setOnClickListener(null)
shareButton.setOnClickListener(null)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.infinum.sentinel.ui.shared
import android.content.Context
import java.io.File
import java.util.Calendar
import java.util.Locale

internal class LogFileResolver(
private val context: Context
Expand All @@ -27,11 +28,12 @@ internal class LogFileResolver(
val year = Calendar.getInstance().get(Calendar.YEAR)

val filename = buildString {
append(String.format("%02d", day))
val locale = Locale.getDefault()
append(String.format(locale = locale, format = "%02d", day))
append("-")
append(String.format("%02d", month))
append(String.format(locale = locale, format = "%02d", month))
append("-")
append(String.format("%04d", year))
append(String.format(locale = locale, format = "%04d", year))
append(LOG_EXTENSION)
}
val nowFile = File("${parent.absolutePath}/$filename")
Expand Down
Loading