@@ -10,14 +10,9 @@ import android.widget.Toast
1010import org.json.JSONObject
1111import org.json.JSONArray
1212
13- import android.content.Intent
14- import android.net.Uri
1513import android.os.Build
16- import androidx.core.content.FileProvider
1714import org.telegram.messenger.AndroidUtilities
1815import org.telegram.messenger.BuildVars
19- import org.telegram.messenger.DownloadController
20- import org.telegram.messenger.FileLoader
2116import org.telegram.messenger.LocaleController
2217import org.telegram.messenger.MessagesController
2318import org.telegram.messenger.UserConfig
@@ -81,7 +76,8 @@ object AppUpdater {
8176 fun checkNewVersion (
8277 parentActivity : Activity ,
8378 context : Context ,
84- callback : (AlertDialog .Builder ? ) -> Int ,
79+ legacyCallback : (AlertDialog .Builder ? ) -> Int ,
80+ modernCallback : (TLRPC .TL_help_appUpdate ? ) -> Int ,
8581 manual : Boolean = false) {
8682
8783 try {
@@ -96,10 +92,10 @@ object AppUpdater {
9692
9793 // Try Telegram channel first if we have an active session
9894 if (UserConfig .getInstance(UserConfig .selectedAccount).isClientActivated()) {
99- checkUpdateFromTelegramChannel(parentActivity, context, callback , manual, currentVersion)
95+ checkUpdateFromTelegramChannel(parentActivity, context, legacyCallback, modernCallback , manual, currentVersion)
10096 } else {
10197 // Fallback to GitHub API
102- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
98+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
10399 }
104100 } catch (e: Exception ) {
105101 android.util.Log .e(" Fork Client" , " Error in checkNewVersion" , e)
@@ -112,7 +108,8 @@ object AppUpdater {
112108 private fun checkUpdateFromTelegramChannel (
113109 parentActivity : Activity ,
114110 context : Context ,
115- callback : (AlertDialog .Builder ? ) -> Int ,
111+ legacyCallback : (AlertDialog .Builder ? ) -> Int ,
112+ modernCallback : (TLRPC .TL_help_appUpdate ? ) -> Int ,
116113 manual : Boolean ,
117114 currentVersion : String ) {
118115
@@ -122,14 +119,14 @@ object AppUpdater {
122119 ConnectionsManager .getInstance(UserConfig .selectedAccount).sendRequest(req) { response, error ->
123120 if (error != null || response !is TLRPC .TL_contacts_resolvedPeer ) {
124121 android.util.Log .w(" Fork Client" , " Failed to resolve update channel, falling back to GitHub" )
125- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
122+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
126123 return @sendRequest
127124 }
128125
129126 val chat = response.chats.firstOrNull()
130127 if (chat == null ) {
131128 android.util.Log .w(" Fork Client" , " Update channel not found, falling back to GitHub" )
132- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
129+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
133130 return @sendRequest
134131 }
135132
@@ -143,14 +140,14 @@ object AppUpdater {
143140 ConnectionsManager .getInstance(UserConfig .selectedAccount).sendRequest(messagesReq) { historyResponse, historyError ->
144141 if (historyError != null || historyResponse !is TLRPC .messages_Messages) {
145142 android.util.Log .w(" Fork Client" , " Failed to get channel history, falling back to GitHub" )
146- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
143+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
147144 return @sendRequest
148145 }
149146
150147 val message = historyResponse.messages.firstOrNull()
151148 if (message?.message == null ) {
152149 android.util.Log .w(" Fork Client" , " No messages in update channel, falling back to GitHub" )
153- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
150+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
154151 return @sendRequest
155152 }
156153
@@ -160,7 +157,7 @@ object AppUpdater {
160157 val androidInfo = updateInfo.optJSONObject(" android" )
161158 if (androidInfo == null ) {
162159 android.util.Log .w(" Fork Client" , " Invalid update JSON format, falling back to GitHub" )
163- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
160+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
164161 return @sendRequest
165162 }
166163
@@ -174,14 +171,14 @@ object AppUpdater {
174171
175172 if (releaseInfo.isEmpty()) {
176173 android.util.Log .w(" Fork Client" , " No version info found, falling back to GitHub" )
177- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
174+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
178175 return @sendRequest
179176 }
180177
181178 val parts = releaseInfo.split(" :" )
182179 if (parts.size != 2 ) {
183180 android.util.Log .w(" Fork Client" , " Invalid version format, falling back to GitHub" )
184- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
181+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
185182 return @sendRequest
186183 }
187184
@@ -190,7 +187,7 @@ object AppUpdater {
190187
191188 if (fileInfo.size != 2 ) {
192189 android.util.Log .w(" Fork Client" , " Invalid file info format, falling back to GitHub" )
193- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
190+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
194191 return @sendRequest
195192 }
196193
@@ -199,7 +196,7 @@ object AppUpdater {
199196
200197 if (messageId == null ) {
201198 android.util.Log .w(" Fork Client" , " Invalid message ID, falling back to GitHub" )
202- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
199+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
203200 return @sendRequest
204201 }
205202
@@ -215,11 +212,11 @@ object AppUpdater {
215212 }
216213
217214 // Get download URL from files channel
218- getDownloadUrlFromFilesChannel(parentActivity, context, callback , newVersion, filesChannelUsername, messageId)
215+ getDownloadUrlFromFilesChannel(parentActivity, context, modernCallback , newVersion, filesChannelUsername, messageId)
219216
220217 } catch (e: Exception ) {
221218 android.util.Log .e(" Fork Client" , " Error parsing update info from Telegram, falling back to GitHub" , e)
222- checkUpdateFromGitHub(parentActivity, context, callback , manual, currentVersion)
219+ checkUpdateFromGitHub(parentActivity, context, legacyCallback , manual, currentVersion)
223220 }
224221 }
225222 }
@@ -228,7 +225,7 @@ object AppUpdater {
228225 private fun getDownloadUrlFromFilesChannel (
229226 parentActivity : Activity ,
230227 context : Context ,
231- callback : (AlertDialog . Builder ? ) -> Int ,
228+ modernCallback : (TLRPC . TL_help_appUpdate ? ) -> Int ,
232229 newVersion : String ,
233230 filesChannelUsername : String ,
234231 messageId : Int ) {
@@ -269,174 +266,33 @@ object AppUpdater {
269266 return @sendRequest
270267 }
271268
272- AndroidUtilities .runOnUIThread {
273- val fullMessage = fileMessage?.message ? : " "
274- val changelog = if (fullMessage.contains(" Changelog:" )) {
275- fullMessage.substringAfter(" Changelog:" ).trim()
276- } else {
277- fullMessage.takeIf { it.isNotEmpty() } ? : " A new version is available."
278- }
279- val builder = AlertDialog .Builder (parentActivity)
280- builder.setTitle(" New version $newVersion " )
281- builder.setMessage(changelog)
282- builder.setMessageTextViewClickable(false )
283- builder.setNegativeButton(LocaleController .getString(" Cancel" , R .string.Cancel ), null )
284- builder.setPositiveButton(" Install" ) { _, _ ->
285- val readReq = TLRPC .TL_channels_readHistory ()
286- readReq.channel = inputChannel
287- readReq.max_id = messageId
288- ConnectionsManager .getInstance(UserConfig .selectedAccount).sendRequest(readReq) { _, _ -> }
289-
290- try {
291- val fileName = " $title -$newVersion .apk"
292- val externalDir = context.getExternalFilesDir(null )
293- val downloadDir = File (externalDir, android.os.Environment .DIRECTORY_DOWNLOADS )
294- if (! downloadDir.exists()) {
295- downloadDir.mkdirs()
296- }
297- val destFile = File (downloadDir, fileName)
298-
299- // Check if file is already downloaded in Telegram cache
300- val fileLoader = FileLoader .getInstance(UserConfig .selectedAccount)
301- val cachedPath = fileLoader.getPathToAttach(document, true )
302-
303- if (cachedPath != null && cachedPath.exists()) {
304- // File already downloaded, install directly
305- Toast .makeText(context, " File already downloaded, installing..." , Toast .LENGTH_SHORT ).show()
306- cachedPath.copyTo(destFile, overwrite = true )
307- installApk(context, destFile)
308- } else {
309- // Start download
310- Toast .makeText(context, " Downloading update..." , Toast .LENGTH_SHORT ).show()
311- fileLoader.loadFile(document, fileMessage, FileLoader .PRIORITY_HIGH , 0 )
312- DownloadController .getInstance(UserConfig .selectedAccount).setDocumentHidden(document.id)
313-
314- // Monitor download progress
315- monitorTelegramDownload(context, document, destFile, newVersion)
316- }
317- } catch (e: Exception ) {
318- android.util.Log .e(" Fork Client" , " Error starting download" , e)
319- Toast .makeText(context, " Download failed: ${e.message} " , Toast .LENGTH_SHORT ).show()
320- }
321- }
322- callback(builder)
269+ val fullMessage = fileMessage.message ? : " "
270+ val changelog = if (fullMessage.contains(" Changelog:" )) {
271+ fullMessage.substringAfter(" Changelog:" ).trim()
272+ } else {
273+ fullMessage.takeIf { it.isNotEmpty() } ? : " A new version is available."
323274 }
324- }
325- }
326- }
327275
328- private fun installApk (context : Context , apkFile : File ) {
329- try {
330- val intent = Intent (Intent .ACTION_VIEW )
331- val apkUri: Uri = if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .N ) {
332- FileProvider .getUriForFile(context, " ${context.packageName} .provider" , apkFile)
333- } else {
334- Uri .fromFile(apkFile)
335- }
276+ val update = TLRPC .TL_help_appUpdate ()
277+ update.version = newVersion
278+ update.text = changelog
279+ update.entities = ArrayList ()
280+ update.document = document
281+ update.url = " "
282+ update.can_not_skip = false
336283
337- intent.setDataAndType(apkUri, " application/vnd.android.package-archive" )
338- intent.addFlags(Intent .FLAG_ACTIVITY_NEW_TASK )
339- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .N ) {
340- intent.addFlags(Intent .FLAG_GRANT_READ_URI_PERMISSION )
341- }
284+ val readReq = TLRPC .TL_channels_readHistory ()
285+ readReq.channel = inputChannel
286+ readReq.max_id = messageId
287+ ConnectionsManager .getInstance(UserConfig .selectedAccount).sendRequest(readReq) { _, _ -> }
342288
343- if (intent.resolveActivity(context.packageManager) != null ) {
344- context.startActivity(intent)
345- } else {
346- android.util.Log .e(" Fork Client" , " No activity to handle APK installation" )
347289 AndroidUtilities .runOnUIThread {
348- Toast .makeText(context, " Cannot install APK automatically " , Toast . LENGTH_SHORT ).show( )
290+ modernCallback(update )
349291 }
350292 }
351- } catch (e: Exception ) {
352- android.util.Log .e(" Fork Client" , " Error installing APK" , e)
353- AndroidUtilities .runOnUIThread {
354- Toast .makeText(context, " Installation error: ${e.message} " , Toast .LENGTH_SHORT ).show()
355- }
356293 }
357294 }
358295
359- private fun monitorTelegramDownload (context : Context , document : TLRPC .Document , destFile : File , version : String ) {
360- Thread {
361- try {
362- val fileLoader = FileLoader .getInstance(UserConfig .selectedAccount)
363- val fileName = FileLoader .getAttachFileName(document)
364- var checkCount = 0
365- val maxChecks = 240
366- var wasLoading = false
367- var loadingStoppedAt = 0
368-
369- android.util.Log .d(" Fork Client" , " Starting download monitor for: $fileName " )
370- android.util.Log .d(" Fork Client" , " Document ID: ${document.id} , DC: ${document.dc_id} , Size: ${document.size} " )
371-
372- while (checkCount < maxChecks) {
373- Thread .sleep(500 )
374- checkCount++
375-
376- val path = fileLoader.getPathToAttach(document, true )
377- val pathFalse = fileLoader.getPathToAttach(document, false )
378- val isLoading = fileLoader.isLoadingFile(fileName)
379-
380- if (isLoading) {
381- wasLoading = true
382- loadingStoppedAt = 0
383- } else if (wasLoading && loadingStoppedAt == 0 ) {
384- loadingStoppedAt = checkCount
385- android.util.Log .d(" Fork Client" , " Loading stopped at check #$checkCount , waiting for file..." )
386- }
387-
388- if (checkCount % 10 == 0 ) {
389- android.util.Log .d(" Fork Client" , " Check #$checkCount : isLoading=$isLoading , wasLoading=$wasLoading " )
390- android.util.Log .d(" Fork Client" , " path(true)=${path?.absolutePath} , exists=${path?.exists()} , size=${path?.length() ? : 0 } " )
391- android.util.Log .d(" Fork Client" , " path(false)=${pathFalse?.absolutePath} , exists=${pathFalse?.exists()} , size=${pathFalse?.length() ? : 0 } " )
392- }
393-
394- val validPath = when {
395- path != null && path.exists() && path.length() > 0 -> path
396- pathFalse != null && pathFalse.exists() && pathFalse.length() > 0 -> pathFalse
397- else -> null
398- }
399-
400- if (validPath != null ) {
401- android.util.Log .d(" Fork Client" , " File downloaded: ${validPath.absolutePath} , size: ${validPath.length()} " )
402-
403- AndroidUtilities .runOnUIThread {
404- Toast .makeText(context, " Download complete, installing..." , Toast .LENGTH_SHORT ).show()
405- }
406-
407- validPath.copyTo(destFile, overwrite = true )
408- downloadId = 0L
409- saveApkPath(context, destFile.absolutePath)
410-
411- AndroidUtilities .runOnUIThread {
412- installApk(context, destFile)
413- }
414- return @Thread
415- }
416-
417- if (loadingStoppedAt > 0 && checkCount - loadingStoppedAt > 40 ) {
418- android.util.Log .w(" Fork Client" , " File not found 20 seconds after download stopped" )
419- android.util.Log .w(" Fork Client" , " Final check - path(true): ${path?.absolutePath} , path(false): ${pathFalse?.absolutePath} " )
420- AndroidUtilities .runOnUIThread {
421- Toast .makeText(context, " Download failed" , Toast .LENGTH_SHORT ).show()
422- }
423- return @Thread
424- }
425- }
426-
427- android.util.Log .w(" Fork Client" , " Download timeout after ${maxChecks * 500 } ms" )
428- AndroidUtilities .runOnUIThread {
429- Toast .makeText(context, " Download timeout" , Toast .LENGTH_SHORT ).show()
430- }
431- } catch (e: Exception ) {
432- android.util.Log .e(" Fork Client" , " Error monitoring download" , e)
433- AndroidUtilities .runOnUIThread {
434- Toast .makeText(context, " Download error: ${e.message} " , Toast .LENGTH_SHORT ).show()
435- }
436- }
437- }.start()
438- }
439-
440296 private fun checkUpdateFromGitHub (
441297 parentActivity : Activity ,
442298 context : Context ,
0 commit comments