Merge 5a8db15725
into dc20a61527
This commit is contained in:
commit
ba691d1c90
|
@ -18,6 +18,7 @@ android {
|
|||
compileSdk 33
|
||||
|
||||
var isBuildSigned = (System.getenv("CI") == "true") && (System.getenv("IS_SKYLINE_SIGNED") == "true")
|
||||
var gitCommitHash = 'git rev-parse --verify HEAD'.execute().text.trim()
|
||||
|
||||
defaultConfig {
|
||||
applicationId "skyline.emu"
|
||||
|
@ -28,6 +29,8 @@ android {
|
|||
versionCode 3
|
||||
versionName "0.0.3"
|
||||
|
||||
buildConfigField("String", "GIT_HASH", "\"${gitCommitHash}\"")
|
||||
|
||||
ndk {
|
||||
//noinspection ChromeOsAbiSupport
|
||||
abiFilters "arm64-v8a"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.vulkan.version"
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline
|
||||
|
||||
import android.app.DownloadManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.Uri
|
||||
import android.text.Html
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.badge.BadgeDrawable.BOTTOM_END
|
||||
import com.google.android.material.badge.BadgeUtils
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.json.JSONTokener
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URL
|
||||
|
||||
class AppUpdater : BroadcastReceiver() {
|
||||
private var downloadID = 0L
|
||||
|
||||
override fun onReceive(context : Context, intent : Intent) {
|
||||
//Fetching the download id received with the broadcast
|
||||
val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
|
||||
//Checking if the received broadcast is for our enqueued download by matching download id
|
||||
if (downloadID == id) {
|
||||
Toast.makeText(context, context.getString(R.string.download_completed), Toast.LENGTH_SHORT).show()
|
||||
|
||||
val intentInstall = Intent(Intent.ACTION_INSTALL_PACKAGE)
|
||||
intentInstall.data = (context.getSystemService(AppCompatActivity.DOWNLOAD_SERVICE) as DownloadManager).getUriForDownloadedFile(downloadID)
|
||||
intentInstall.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
startActivity(context, intentInstall, null)
|
||||
context.unregisterReceiver(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadApk(applicationContext : Context, uri : Uri) {
|
||||
val downloadPath = applicationContext.getPublicFilesDir().canonicalPath
|
||||
val file = File(downloadPath, "skyline.apk")
|
||||
|
||||
if (File(file.path).exists()) {
|
||||
File(file.path).delete()
|
||||
}
|
||||
|
||||
val request = DownloadManager.Request(uri).setTitle("skyline")
|
||||
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
|
||||
.setDestinationUri(Uri.fromFile(file))
|
||||
|
||||
val downloadManager = applicationContext.getSystemService(AppCompatActivity.DOWNLOAD_SERVICE) as DownloadManager
|
||||
downloadID = downloadManager.enqueue(request)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val baseUrl = "https://skyline-builds.alula.gay"
|
||||
private const val branch = "ftx1"
|
||||
|
||||
fun checkForUpdates(applicationContext : Context) {
|
||||
val builder = AlertDialog.Builder(applicationContext)
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val newestBuild = checkRemoteForUpdates()
|
||||
if (newestBuild != null) {
|
||||
val commit = newestBuild.getJSONObject("commit")
|
||||
val remoteBuildGitHash = commit.getString("id")
|
||||
if (BuildConfig.GIT_HASH != remoteBuildGitHash) {
|
||||
val id = newestBuild.get("id")
|
||||
val apkName = newestBuild.get("apkName")
|
||||
val uri = Uri.parse("$baseUrl/cache/${id}/${apkName}")
|
||||
|
||||
val message = commit.getString("message")
|
||||
var changelog = "<b>${applicationContext.getString(R.string.changelog)}</b><p>${message.substringBefore("\n")}</p>"
|
||||
if (message.contains("\n"))
|
||||
changelog += "<p>${message.substringAfter("\n")}</p>"
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
builder.setTitle("${applicationContext.getString(R.string.new_version)} ${newestBuild.get("runNumber")}")
|
||||
.setMessage(Html.fromHtml(changelog, 0))
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(applicationContext.getString(R.string.update)) { dialogInterface, _ ->
|
||||
val receiver = AppUpdater()
|
||||
applicationContext.registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
|
||||
receiver.downloadApk(applicationContext, uri)
|
||||
dialogInterface.dismiss()
|
||||
}.setNegativeButton(applicationContext.getString(R.string.cancel)){ dialogInterface, _ ->
|
||||
dialogInterface.cancel()
|
||||
}.show()
|
||||
}
|
||||
} else {
|
||||
withContext(Dispatchers.Main) {
|
||||
builder.setTitle(applicationContext.getString(R.string.no_updates_available))
|
||||
.setMessage(Html.fromHtml("<b>${applicationContext.getString(R.string.changelog)}</b><p>${commit.getString("message")}</p>", 0))
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(applicationContext.getString(R.string.close)) { dialogInterface, _ ->
|
||||
dialogInterface.dismiss()
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@com.google.android.material.badge.ExperimentalBadgeUtils
|
||||
fun notifyUpdateBadge(context : Context, icon : ImageView) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val newestBuild = checkRemoteForUpdates()
|
||||
if (newestBuild != null) {
|
||||
val remoteBuildGitHash = newestBuild.getJSONObject("commit").getString("id")
|
||||
if (BuildConfig.GIT_HASH != remoteBuildGitHash) {
|
||||
val badge = BadgeDrawable.create(context)
|
||||
badge.badgeGravity = BOTTOM_END
|
||||
badge.verticalOffset = 25
|
||||
badge.horizontalOffset = 25
|
||||
badge.backgroundColor = ContextCompat.getColor(context, R.color.colorPrimary)
|
||||
BadgeUtils.attachBadgeDrawable(badge, icon)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkRemoteForUpdates() : JSONObject? {
|
||||
val url = URL("$baseUrl/builds")
|
||||
try {
|
||||
val response = url.readText()
|
||||
val jsonBuilds = JSONTokener(response).nextValue() as JSONArray
|
||||
|
||||
var ftx1Index = 0
|
||||
while (ftx1Index < jsonBuilds.length() && jsonBuilds.getJSONObject(ftx1Index).get("branch") != branch) {
|
||||
ftx1Index++
|
||||
}
|
||||
if (ftx1Index >= jsonBuilds.length())
|
||||
ftx1Index = 0
|
||||
|
||||
return jsonBuilds.getJSONObject(ftx1Index)
|
||||
} catch (e : IOException) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun removeApk(){
|
||||
if (File(SkylineApplication.instance.getPublicFilesDir().canonicalPath + "/skyline.apk").exists()) {
|
||||
File(SkylineApplication.instance.getPublicFilesDir().canonicalPath + "/skyline.apk").delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -291,6 +291,18 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
binding.checkUpdatesIcon.apply {
|
||||
if (BuildConfig.FLAVOR == "edge") {
|
||||
visibility = View.GONE
|
||||
} else {
|
||||
AppUpdater.removeApk()
|
||||
AppUpdater.notifyUpdateBadge(context, this)
|
||||
this.setOnClickListener {
|
||||
AppUpdater.checkForUpdates(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!-- drawable/download.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorOnSecondary" android:pathData="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" />
|
||||
</vector>
|
|
@ -40,12 +40,28 @@
|
|||
android:padding="5dp"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sub_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/log_icon"
|
||||
app:layout_constraintEnd_toStartOf="@id/check_updates_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/title_text"
|
||||
app:srcCompat="@drawable/ic_refresh"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/check_updates_icon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/check_updates"
|
||||
android:padding="5dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sub_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/log_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/title_text"
|
||||
app:srcCompat="@drawable/ic_check_updates"
|
||||
app:tint="?android:attr/textColorSecondary"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/log_icon"
|
||||
android:layout_width="30dp"
|
||||
|
|
|
@ -10,9 +10,17 @@
|
|||
<string name="settings">Settings</string>
|
||||
<string name="share_logs">Share Logs</string>
|
||||
<string name="refresh">Refresh</string>
|
||||
<string name="check_updates">Check for updates</string>
|
||||
<!-- Toolbar - Share Logs -->
|
||||
<string name="log_share_prompt">Share log file</string>
|
||||
<string name="logs_not_found">No logs were created during the last run</string>
|
||||
<!-- Updater -->
|
||||
<string name="new_version">New version</string>
|
||||
<string name="changelog">Changelog</string>
|
||||
<string name="update">Update</string>
|
||||
<string name="download_completed">Download completed</string>
|
||||
<string name="no_updates_available">No updates available</string>
|
||||
<string name="close">Close</string>
|
||||
<!-- Main -->
|
||||
<string name="all">All</string>
|
||||
<string name="metadata_missing">Metadata Missing</string>
|
||||
|
|
Loading…
Reference in New Issue