Check if in-app update allowed
This commit is contained in:
@@ -15,7 +15,7 @@ android {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode gitCommits
|
||||
versionName '0.2-b1'
|
||||
versionName '0.3'
|
||||
|
||||
buildConfigField 'String', 'GIT_BRANCH', "\"${gitBranch}\""
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.koitharu.kotatsu.ui.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
@@ -22,8 +24,18 @@ import org.koitharu.kotatsu.core.github.VersionId
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.ui.common.BaseService
|
||||
import org.koitharu.kotatsu.utils.FileSizeUtils
|
||||
import org.koitharu.kotatsu.utils.ext.byte2HexFormatted
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.security.cert.CertificateEncodingException
|
||||
import java.security.cert.CertificateException
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class AppUpdateService : BaseService() {
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
@@ -92,25 +104,26 @@ class AppUpdateService : BaseService() {
|
||||
)
|
||||
builder.setSmallIcon(R.drawable.ic_stat_update)
|
||||
builder.setAutoCancel(true)
|
||||
builder.setColor(ContextCompat.getColor(this, R.color.blue_primary_dark))
|
||||
builder.color = ContextCompat.getColor(this, R.color.blue_primary_dark)
|
||||
builder.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
|
||||
manager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val CERT_SHA1 = "2C:19:C7:E8:07:61:2B:8E:94:51:1B:FD:72:67:07:64:5D:C2:58:AE"
|
||||
private const val NOTIFICATION_ID = 202
|
||||
private const val CHANNEL_ID = "update"
|
||||
private val PERIOD = TimeUnit.HOURS.toMillis(6)
|
||||
|
||||
fun start(context: Context) {
|
||||
try {
|
||||
context.startService(Intent(context, AppUpdateService::class.java))
|
||||
} catch (_: IllegalStateException) {
|
||||
}
|
||||
fun isUpdateSupported(context: Context): Boolean {
|
||||
return getCertificateSHA1Fingerprint(context) == CERT_SHA1
|
||||
}
|
||||
|
||||
fun startIfRequired(context: Context) {
|
||||
if (!isUpdateSupported(context)) {
|
||||
return
|
||||
}
|
||||
val settings = AppSettings(context)
|
||||
if (settings.appUpdateAuto) {
|
||||
val lastUpdate = settings.appUpdate
|
||||
@@ -119,5 +132,47 @@ class AppUpdateService : BaseService() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun start(context: Context) {
|
||||
try {
|
||||
context.startService(Intent(context, AppUpdateService::class.java))
|
||||
} catch (_: IllegalStateException) {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@SuppressLint("PackageManagerGetSignatures")
|
||||
private fun getCertificateSHA1Fingerprint(context: Context): String? {
|
||||
val packageInfo = try {
|
||||
context.packageManager.getPackageInfo(
|
||||
context.packageName,
|
||||
PackageManager.GET_SIGNATURES
|
||||
)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
val signatures = packageInfo?.signatures
|
||||
val cert: ByteArray = signatures?.firstOrNull()?.toByteArray() ?: return null
|
||||
val input: InputStream = ByteArrayInputStream(cert)
|
||||
val c = try {
|
||||
val cf = CertificateFactory.getInstance("X509")
|
||||
cf.generateCertificate(input) as X509Certificate
|
||||
} catch (e: CertificateException) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
return try {
|
||||
val md: MessageDigest = MessageDigest.getInstance("SHA1")
|
||||
val publicKey: ByteArray = md.digest(c.getEncoded())
|
||||
publicKey.byte2HexFormatted()
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
} catch (e: CertificateEncodingException) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,9 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings),
|
||||
}
|
||||
findPreference<MultiSelectListPreference>(R.string.key_reader_switchers)?.summaryProvider =
|
||||
MultiSummaryProvider(R.string.gestures_only)
|
||||
findPreference<Preference>(R.string.key_app_update_auto)?.run {
|
||||
isVisible = AppUpdateService.isUpdateSupported(context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import android.net.Uri
|
||||
import java.net.URLEncoder
|
||||
import java.util.*
|
||||
|
||||
fun String.longHashCode(): Long {
|
||||
var h = 1125899906842597L
|
||||
@@ -72,4 +73,23 @@ fun String.toUriOrNull(): Uri? = if (isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
Uri.parse(this)
|
||||
}
|
||||
|
||||
fun ByteArray.byte2HexFormatted(): String? {
|
||||
val str = StringBuilder(size * 2)
|
||||
for (i in indices) {
|
||||
var h = Integer.toHexString(this[i].toInt())
|
||||
val l = h.length
|
||||
if (l == 1) {
|
||||
h = "0$h"
|
||||
}
|
||||
if (l > 2) {
|
||||
h = h.substring(l - 2, l)
|
||||
}
|
||||
str.append(h.toUpperCase(Locale.ROOT))
|
||||
if (i < size - 1) {
|
||||
str.append(':')
|
||||
}
|
||||
}
|
||||
return str.toString()
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="-1"
|
||||
@@ -32,9 +33,9 @@
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="org.koitharu.kotatsu.ui.settings.sources.SourcesSettingsFragment"
|
||||
android:key="@string/key_remote_sources"
|
||||
android:title="@string/remote_sources"
|
||||
app:allowDividerAbove="true"
|
||||
android:key="@string/key_remote_sources"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<PreferenceScreen
|
||||
@@ -53,8 +54,8 @@
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:title="@string/pages_animation"
|
||||
android:key="@string/key_reader_animation"
|
||||
android:title="@string/pages_animation"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<PreferenceCategory
|
||||
@@ -67,7 +68,9 @@
|
||||
android:key="@string/key_app_update_auto"
|
||||
android:summary="@string/show_notification_app_update"
|
||||
android:title="@string/application_update"
|
||||
app:iconSpaceReserved="false" />
|
||||
app:iconSpaceReserved="false"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
@@ -77,10 +80,10 @@
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<Preference
|
||||
android:title="@string/notifications_settings"
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/key_tracker_notifications"
|
||||
android:key="@string/key_notifications_settings" />
|
||||
android:key="@string/key_notifications_settings"
|
||||
android:title="@string/notifications_settings"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user