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

Corrections after 1.8.1 release #474

Merged
merged 16 commits into from
Dec 26, 2024
Merged
Prev Previous commit
Next Next commit
Simplify UpdateManager
Reco1I committed Dec 18, 2024
commit 82b61f367e3eff80d489968f7d9eb292f8fbfd8c
229 changes: 82 additions & 147 deletions src/com/reco1l/osu/UpdateManager.kt
Original file line number Diff line number Diff line change
@@ -7,60 +7,53 @@ import androidx.core.content.FileProvider
import com.osudroid.resources.R
import com.edlplan.ui.fragment.MarkdownFragment
import com.reco1l.framework.net.FileRequest
import com.reco1l.framework.net.IDownloaderObserver
import com.reco1l.framework.net.IFileRequestObserver
import com.reco1l.framework.net.JsonObjectRequest
import com.reco1l.osu.ui.MessageDialog
import com.reco1l.osu.ui.ProgressDialog
import ru.nsu.ccfit.zuev.osu.Config
import ru.nsu.ccfit.zuev.osu.GlobalManager
import ru.nsu.ccfit.zuev.osu.MainActivity
import ru.nsu.ccfit.zuev.osu.ToastLogger
import ru.nsu.ccfit.zuev.osu.helper.StringTable
import ru.nsu.ccfit.zuev.osu.online.OnlineManager.updateEndpoint
import ru.nsu.ccfit.zuev.osuplus.BuildConfig
import ru.nsu.ccfit.zuev.osuplus.BuildConfig.APPLICATION_ID
import java.io.File


object UpdateManager: IDownloaderObserver
object UpdateManager: IFileRequestObserver
{

private val updatesDirectory = File(Config.getCachePath(), "updates").apply(File::mkdirs)
private val apksDirectory = File(Config.getCachePath(), "updates").apply(File::mkdirs)


private var downloadURL: String? = null

private var newVersionCode: Long = GlobalManager.getInstance().mainActivity.versionCode

private var progressDialog: ProgressDialog? = null


@JvmStatic
fun onActivityStart(activity: MainActivity) = mainThread {

// Finding if there's a "pending changelog". This means the game was previously updated, we're
// showing the changelog after update with a prompt asking user to show.
fun onActivityStart() = mainThread {

val latestUpdate = Config.getLong("latestVersionCode", activity.versionCode)
val pendingChangelog = Config.getString("pendingChangelog", null)
val activity = GlobalManager.getInstance().mainActivity
val version = Config.getLong("version", activity.versionCode)

if (!pendingChangelog.isNullOrEmpty()) {
// Ignoring debug because otherwise every compiled build will show the dialog.
if (!BuildConfig.DEBUG && version < activity.versionCode) {

if (latestUpdate > activity.versionCode) {
MessageDialog()
.setTitle(StringTable.get(R.string.update_info_updated))
.setMessage("Game was updated to a newer version.\nDo you want to see the changelog?")
.addButton("Yes") {
it.dismiss()

MessageDialog()
.setTitle(activity.getString(R.string.update_info_updated))
.setMessage("Game was updated to a newer version. Do you want to see the changelog?")
.addButton("Yes") {
MarkdownFragment()
.setTitle(R.string.changelog_title)
.setMarkdown(pendingChangelog)
.show()
MarkdownFragment()
.setTitle(R.string.changelog_title)
.setMarkdown(activity.assets.open("app/changelog.md").reader().readText())
.show()
}
.addButton("No", clickListener = MessageDialog::dismiss)
.show()

it.dismiss()
}
.addButton("No") { it.dismiss() }
.setOnDismiss { Config.setString("pendingChangelog", null) }
.show()
}
Config.setLong("version", activity.versionCode)
}

checkNewUpdates(true)
@@ -69,69 +62,64 @@ object UpdateManager: IDownloaderObserver
/**
* Check for new game updates.
*
* @param silently If `true` no prompt will be shown unless there's new updates.
* @param silently If `true` no announce will be shown unless there's new updates.
*/
@JvmStatic
fun checkNewUpdates(silently: Boolean) {

val mainActivity = GlobalManager.getInstance().mainActivity

if (!silently) {
ToastLogger.showText(R.string.update_info_checking, false)
}

async {
// Cleaning up old updates.
apksDirectory.listFiles()?.forEach { it.delete() }

// Cleaning update directory first, checking if there's a newer package downloaded already.
updatesDirectory.listFiles()?.also { list ->

var newestVersionDownloaded = mainActivity.versionCode

list.forEach {

val version = it.nameWithoutExtension.toLongOrNull() ?: return@forEach
if (version == mainActivity.versionCode) {
it.delete()
}

if (version > newestVersionDownloaded) {
newestVersionDownloaded = version
}
}

if (newestVersionDownloaded > mainActivity.versionCode) {
newVersionCode = newestVersionDownloaded
onFoundNewUpdate(silently)
return@async
}
}

try {

// Avoid new request if it was already done.
if (downloadURL != null) {
onFoundNewUpdate(silently)
return@async
}

JsonObjectRequest(/*updateEndpoint*/ "http://localhost:80/update.php").use { request ->

request.buildRequest { header("User-Agent", "Chrome/Android") }
JsonObjectRequest(updateEndpoint).use { request ->

val response = request.execute().json
val changelog = response.getString("changelog")

downloadURL = response.getString("link")
newVersionCode = response.getLong("version_code")
val newVersion = response.getLong("version_code")
val link = response.getString("link")

// Previous implementation has this check, server returning an older version shouldn't happen.
if (newVersionCode <= mainActivity.versionCode) {
ToastLogger.showText(R.string.update_info_latest, false)
return@async
if (newVersion <= GlobalManager.getInstance().mainActivity.versionCode) {
if (!silently) {
ToastLogger.showText(R.string.update_info_latest, false)
}
return@use
}

Config.setString("pendingChangelog", changelog)
onFoundNewUpdate(silently)
MessageDialog()
.setTitle("New update available!")
.setMessage(StringTable.get(R.string.update_dialog_message))
.addButton(StringTable.get(R.string.update_dialog_button_update)) { dialog ->

dialog.dismiss()

progressDialog = ProgressDialog().apply {
indeterminate = true
allowDismiss = false
max = 100
title = "Downloading update"
message = StringTable.format(R.string.update_info_downloading, 0)
show()
}

async {
val file = File(apksDirectory, "${newVersion}.apk")
if (file.exists()) {
file.delete()
}
file.createNewFile()

val fileRequest = FileRequest(file, link)
fileRequest.observer = this@UpdateManager
fileRequest.execute()
}
}
.addButton("Update later") { it.dismiss() }
.show()
}

} catch (e: Exception) {
@@ -145,92 +133,39 @@ object UpdateManager: IDownloaderObserver
}


private fun onFoundNewUpdate(silently: Boolean) = mainThread {

val activity = GlobalManager.getInstance().mainActivity
override fun onDownloadUpdate(request: FileRequest) = mainThread {
val progress = request.progress.toInt()

if (newVersionCode <= activity.versionCode) {
if (!silently) {
ToastLogger.showText(R.string.update_info_latest, false)
}
return@mainThread
}

Config.setLong("latestVersionCode", newVersionCode)

MessageDialog()
.setTitle("New update available!")
.setMessage(activity.getString(R.string.update_dialog_message))
.addButton(activity.getString(R.string.update_dialog_button_update)) {

val file = File(updatesDirectory, "$newVersionCode.apk")

// Files is already downloaded, navigating to installation.
if (file.exists()) {
installAPK(file)
return@addButton
}

file.createNewFile()
downloadAPK(file)
}
.addButton("Update later") { it.dismiss() }
.show()
progressDialog?.indeterminate = false
progressDialog?.progress = progress
progressDialog?.setMessage(StringTable.format(R.string.update_info_downloading, progress))
}

override fun onDownloadEnd(request: FileRequest) {
mainThread { progressDialog?.dismiss() }

private fun installAPK(file: File) {

val uri = FileProvider.getUriForFile(GlobalManager.getInstance().mainActivity, "$APPLICATION_ID.fileProvider", file)
val activity = GlobalManager.getInstance().mainActivity
val uri = FileProvider.getUriForFile(activity, "$APPLICATION_ID.fileProvider", request.file)

val intent = Intent(ACTION_VIEW)
intent.setDataAndType(uri, "application/vnd.android.package-archive")
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION)

GlobalManager.getInstance().mainActivity.startActivity(intent)
activity.startActivity(intent)
}

private fun downloadAPK(file: File) {

// Empty string: At this point download URL shouldn't be null but if it is the case (which is weird) we set an
// empty string so the downloader invokes onDownloadFail() and a prompt is shown to user rather than nothing.
val url = downloadURL ?: ""

async {
val downloader = FileRequest(file, url)
downloader.observer = this@UpdateManager
downloader.execute()

mainThread {
progressDialog = ProgressDialog().apply {
setIndeterminate(true)
setTitle("Downloading update")
setMessage(StringTable.format(R.string.update_info_downloading, 0))
show()
}
}
}
}


override fun onDownloadUpdate(downloader: FileRequest) = mainThread {
progressDialog?.progress = downloader.progress.toInt()
progressDialog?.setMessage(StringTable.format(R.string.update_info_downloading, downloader.progress.toInt()))
}

override fun onDownloadEnd(downloader: FileRequest) {
progressDialog?.dismiss()
installAPK(downloader.file)
}

override fun onDownloadFail(downloader: FileRequest, exception: Exception) {
override fun onDownloadFail(request: FileRequest, exception: Exception) {
Log.e("UpdateManager", "Failed to download update.", exception)
ToastLogger.showText(R.string.update_info_download_failed, false)
downloader.file.delete()

mainThread { progressDialog?.dismiss() }
request.file.delete()
}

override fun onDownloadCancel(downloader: FileRequest) {
override fun onDownloadCancel(request: FileRequest) {
ToastLogger.showText(R.string.update_info_download_canceled, false)
downloader.file.delete()

mainThread { progressDialog?.dismiss() }
request.file.delete()
}
}
10 changes: 3 additions & 7 deletions src/ru/nsu/ccfit/zuev/osu/MainActivity.java
Original file line number Diff line number Diff line change
@@ -304,7 +304,7 @@ public void onLoadComplete() {

Execution.delayed(2500, () -> {

UpdateManager.onActivityStart(this);
UpdateManager.onActivityStart();
GlobalManager.getInstance().setInfo("");
GlobalManager.getInstance().setLoadingProgress(100);
ResourceManager.getInstance().loadFont("font", null, 28, Color.WHITE);
@@ -368,7 +368,7 @@ protected void onSetContentView() {
this.mRenderSurfaceView.setRenderer(this.mEngine);

RelativeLayout layout = new RelativeLayout(this);
layout.setBackgroundColor(Color.argb(255, 0, 0, 0));
layout.setBackgroundColor(Color.BLACK);
layout.addView(
mRenderSurfaceView,
new RelativeLayout.LayoutParams(
@@ -378,13 +378,9 @@ protected void onSetContentView() {
}});

FrameLayout frameLayout = new FrameLayout(this);
frameLayout.setId(0x28371);
frameLayout.setId(View.generateViewId());
layout.addView(frameLayout, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

View c = new View(this);
c.setBackgroundColor(Color.argb(0, 0, 0, 0));
layout.addView(c, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

this.setContentView(
layout,
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) {{