RemoteSharedLibraryManager.kt (4869B) - raw
1 package me.rhunk.snapenhance 2 3 import android.annotation.SuppressLint 4 import android.app.Notification 5 import android.app.NotificationChannel 6 import android.app.NotificationManager 7 import android.app.PendingIntent 8 import android.content.Intent 9 import android.os.Build 10 import androidx.core.net.toUri 11 import me.rhunk.snapenhance.common.BuildConfig 12 import me.rhunk.snapenhance.common.bridge.InternalFileHandleType 13 import okhttp3.OkHttpClient 14 import okhttp3.Request 15 import java.io.File 16 17 class RemoteSharedLibraryManager( 18 private val remoteSideContext: RemoteSideContext 19 ) { 20 private val okHttpClient = OkHttpClient() 21 22 private fun getVersion(): String? { 23 return runCatching { 24 okHttpClient.newCall( 25 Request.Builder() 26 .url("${BuildConfig.SIF_ENDPOINT}/version") 27 .build() 28 ).execute().use { response -> 29 if (!response.isSuccessful) { 30 return null 31 } 32 response.body.string() 33 } 34 }.getOrNull() 35 } 36 37 private fun downloadLatest(outputFile: File): Boolean { 38 val abi = Build.SUPPORTED_ABIS.firstOrNull() ?: return false 39 val request = Request.Builder() 40 .url("${BuildConfig.SIF_ENDPOINT}/$abi.so") 41 .build() 42 runCatching { 43 okHttpClient.newCall(request).execute().use { response -> 44 if (!response.isSuccessful) { 45 return false 46 } 47 response.body.byteStream().use { input -> 48 outputFile.outputStream().use { output -> 49 input.copyTo(output) 50 } 51 } 52 return true 53 } 54 }.onFailure { 55 remoteSideContext.log.error("Failed to download latest sif", it) 56 } 57 return false 58 } 59 60 @SuppressLint("ApplySharedPref") 61 fun init() { 62 val libraryFile = InternalFileHandleType.SIF.resolve(remoteSideContext.androidContext) 63 val currentVersion = remoteSideContext.sharedPreferences.getString("sif", null)?.trim() 64 if (currentVersion == null || currentVersion == "false") { 65 libraryFile.takeIf { it.exists() }?.delete() 66 remoteSideContext.log.info("sif can't be loaded due to user preference") 67 return 68 } 69 val latestVersion = getVersion()?.trim() ?: run { 70 throw Exception("Failed to get latest sif version") 71 } 72 73 if (currentVersion == latestVersion) { 74 remoteSideContext.log.info("sif is up to date ($currentVersion)") 75 return 76 } 77 78 remoteSideContext.log.info("Updating sif from $currentVersion to $latestVersion") 79 if (downloadLatest(libraryFile)) { 80 remoteSideContext.sharedPreferences.edit().putString("sif", latestVersion).commit() 81 remoteSideContext.shortToast("SIF updated to $latestVersion!") 82 83 if (currentVersion.isNotEmpty()) { 84 val notificationManager = remoteSideContext.androidContext.getSystemService(NotificationManager::class.java) 85 val channelId = "sif_update" 86 87 notificationManager.createNotificationChannel( 88 NotificationChannel( 89 channelId, 90 "SIF Updates", 91 NotificationManager.IMPORTANCE_DEFAULT 92 ) 93 ) 94 95 notificationManager.notify( 96 System.nanoTime().toInt(), 97 Notification.Builder(remoteSideContext.androidContext, channelId) 98 .setContentTitle("SnapEnhance") 99 .setContentText("Security Features have been updated to version $latestVersion") 100 .setSmallIcon(android.R.drawable.stat_sys_download_done) 101 .setContentIntent(PendingIntent.getActivity( 102 remoteSideContext.androidContext, 103 0, 104 Intent().apply { 105 action = Intent.ACTION_VIEW 106 data = "https://github.com/SnapEnhance/resources".toUri() 107 flags = Intent.FLAG_ACTIVITY_NEW_TASK 108 }, 109 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE 110 )).build() 111 ) 112 } 113 114 // force restart snapchat 115 runCatching { 116 remoteSideContext.config.configStateListener?.takeIf { it.asBinder().pingBinder() }?.onRestartRequired() 117 } 118 } else { 119 remoteSideContext.log.warn("Failed to download latest sif") 120 throw Exception("Failed to download latest sif") 121 } 122 } 123 }