2025-02-15 19:21:00 +01:00
|
|
|
package me.lecaro.breakout
|
2025-03-18 14:16:12 +01:00
|
|
|
|
2025-03-17 11:50:13 +01:00
|
|
|
import android.app.Activity
|
|
|
|
import android.app.DownloadManager
|
2025-03-18 15:26:56 +01:00
|
|
|
import android.content.ContentValues
|
2025-03-17 11:50:13 +01:00
|
|
|
import android.content.Context
|
|
|
|
import android.content.Intent
|
2025-03-18 14:16:12 +01:00
|
|
|
import android.content.pm.PackageManager
|
2025-03-17 11:50:13 +01:00
|
|
|
import android.net.Uri
|
2025-03-18 15:26:56 +01:00
|
|
|
import android.os.Build
|
2025-02-15 19:21:00 +01:00
|
|
|
import android.os.Bundle
|
2025-03-17 11:50:13 +01:00
|
|
|
import android.os.Environment
|
2025-03-18 15:26:56 +01:00
|
|
|
import android.provider.MediaStore
|
2025-02-15 19:21:00 +01:00
|
|
|
import android.util.Log
|
|
|
|
import android.view.Window
|
|
|
|
import android.view.WindowManager
|
|
|
|
import android.webkit.ConsoleMessage
|
2025-03-17 11:50:13 +01:00
|
|
|
import android.webkit.DownloadListener
|
|
|
|
import android.webkit.ValueCallback
|
2025-02-15 19:21:00 +01:00
|
|
|
import android.webkit.WebChromeClient
|
|
|
|
import android.webkit.WebView
|
2025-03-17 11:50:13 +01:00
|
|
|
import android.widget.Toast
|
|
|
|
import java.io.File
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.util.Date
|
2025-03-18 14:16:12 +01:00
|
|
|
import java.util.jar.Manifest
|
2025-02-20 11:34:11 +01:00
|
|
|
|
2025-03-17 11:50:13 +01:00
|
|
|
const val CHOOSE_FILE_REQUEST_CODE = 548459
|
2025-03-18 14:16:12 +01:00
|
|
|
const val PERM_REQUEST_CODE = 66622635
|
|
|
|
|
2025-02-15 19:21:00 +01:00
|
|
|
class MainActivity : android.app.Activity() {
|
2025-03-17 11:50:13 +01:00
|
|
|
|
|
|
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
|
|
|
|
|
|
super.onActivityResult(requestCode, resultCode, data)
|
|
|
|
when (requestCode) {
|
|
|
|
CHOOSE_FILE_REQUEST_CODE -> {
|
|
|
|
if (resultCode == RESULT_OK) {
|
2025-03-18 14:16:12 +01:00
|
|
|
filePathCallback?.onReceiveValue(
|
|
|
|
WebChromeClient.FileChooserParams.parseResult(
|
2025-03-18 15:26:56 +01:00
|
|
|
resultCode, data
|
2025-03-18 14:16:12 +01:00
|
|
|
)
|
|
|
|
)
|
2025-03-17 11:50:13 +01:00
|
|
|
filePathCallback = null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-03-18 15:26:56 +01:00
|
|
|
|
2025-03-17 11:50:13 +01:00
|
|
|
var filePathCallback: ValueCallback<Array<Uri>>? = null
|
2025-03-18 14:16:12 +01:00
|
|
|
|
2025-03-18 15:26:56 +01:00
|
|
|
private fun downloadFile(url: String) {
|
|
|
|
try {
|
2025-03-18 14:16:12 +01:00
|
|
|
if (!url.startsWith("data:")) {
|
|
|
|
Log.w("DL", "url ignored because it does not start with data:")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
val sdf = SimpleDateFormat("yyyy-M-dd-hh-mm")
|
|
|
|
val currentDate = sdf.format(Date())
|
2025-03-18 15:26:56 +01:00
|
|
|
val base64Data = url.substringAfterLast(',')
|
|
|
|
val decodedBytes = android.util.Base64.decode(base64Data, android.util.Base64.DEFAULT)
|
2025-03-18 14:16:12 +01:00
|
|
|
|
|
|
|
if (url.startsWith("data:application/json;base64,")) {
|
2025-03-18 15:26:56 +01:00
|
|
|
writeFile(decodedBytes, "breakout-71-save-$currentDate.b71", "application/b71")
|
2025-03-18 14:16:12 +01:00
|
|
|
|
|
|
|
} else if (url.startsWith("data:video/webm;base64,")) {
|
2025-03-18 15:26:56 +01:00
|
|
|
writeFile(decodedBytes, "breakout-71-gameplay-capture-$currentDate.webm", "application/b71")
|
2025-03-18 14:16:12 +01:00
|
|
|
} else {
|
|
|
|
Log.w("DL", "unexpected type " + url)
|
|
|
|
}
|
2025-03-18 15:26:56 +01:00
|
|
|
} catch (e: Exception) {
|
|
|
|
Log.e("DL", "Error ${e.message}")
|
|
|
|
Toast.makeText(this, "Error ${e.message}", Toast.LENGTH_LONG).show()
|
|
|
|
}
|
|
|
|
}
|
2025-03-18 14:16:12 +01:00
|
|
|
|
2025-03-18 15:26:56 +01:00
|
|
|
fun writeFile(decodedBytes:ByteArray,fileName:String, mime:String){
|
2025-03-18 14:16:12 +01:00
|
|
|
|
|
|
|
|
2025-03-18 15:26:56 +01:00
|
|
|
|
|
|
|
val jsonData = String(decodedBytes);
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
|
|
|
|
|
|
|
|
|
|
val contentValues = ContentValues().apply {
|
|
|
|
put(MediaStore.Downloads.DISPLAY_NAME, fileName)
|
|
|
|
put(MediaStore.Downloads.MIME_TYPE,mime )
|
|
|
|
put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
|
|
|
|
}
|
|
|
|
|
|
|
|
val uri: Uri? = contentResolver.insert(
|
|
|
|
MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues
|
|
|
|
)
|
|
|
|
uri?.let {
|
|
|
|
contentResolver.openOutputStream(it)?.use { outputStream ->
|
|
|
|
outputStream.write(decodedBytes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
val shareIntent: Intent = Intent().apply {
|
|
|
|
action = Intent.ACTION_SEND
|
|
|
|
// Example: content://com.google.android.apps.photos.contentprovider/...
|
|
|
|
putExtra(Intent.EXTRA_STREAM, uri)
|
|
|
|
type = mime
|
|
|
|
}
|
|
|
|
startActivity(Intent.createChooser(shareIntent, null))
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
|
|
val dir = getExternalFilesDir(null)
|
|
|
|
val file = File(dir, fileName)
|
|
|
|
file.writeText(jsonData)
|
|
|
|
Toast.makeText(this, "Saved in $dir", Toast.LENGTH_LONG).show()
|
|
|
|
|
|
|
|
}
|
2025-03-18 14:16:12 +01:00
|
|
|
}
|
2025-03-18 15:26:56 +01:00
|
|
|
|
2025-02-15 19:21:00 +01:00
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
|
|
window.setFlags(
|
2025-03-18 15:26:56 +01:00
|
|
|
WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN
|
2025-02-15 19:21:00 +01:00
|
|
|
);
|
|
|
|
val webView = WebView(this)
|
|
|
|
webView.settings.javaScriptEnabled = true
|
|
|
|
webView.settings.domStorageEnabled = true
|
2025-03-17 11:50:13 +01:00
|
|
|
webView.settings.setSupportZoom(false)
|
|
|
|
|
2025-03-18 14:16:12 +01:00
|
|
|
webView.loadUrl("file:///android_asset/index.html?isInWebView=true")
|
2025-03-18 15:26:56 +01:00
|
|
|
val activity = this;
|
2025-03-17 11:50:13 +01:00
|
|
|
|
2025-02-15 19:21:00 +01:00
|
|
|
webView.webChromeClient = object : WebChromeClient() {
|
|
|
|
override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
|
|
|
|
Log.d(
|
2025-03-18 15:26:56 +01:00
|
|
|
"WebView",
|
|
|
|
"${consoleMessage.message()} -- From line " + "${consoleMessage.lineNumber()} of ${consoleMessage.sourceId()}"
|
2025-02-15 19:21:00 +01:00
|
|
|
)
|
|
|
|
return true
|
|
|
|
}
|
2025-03-17 11:50:13 +01:00
|
|
|
|
2025-03-18 14:16:12 +01:00
|
|
|
override fun onShowFileChooser(
|
|
|
|
webView: WebView?,
|
|
|
|
filePathCallback: ValueCallback<Array<Uri>>?,
|
|
|
|
fileChooserParams: FileChooserParams?
|
|
|
|
): Boolean {
|
2025-03-18 15:26:56 +01:00
|
|
|
try {
|
2025-03-18 14:16:12 +01:00
|
|
|
|
2025-03-18 15:26:56 +01:00
|
|
|
startActivityForResult(
|
|
|
|
fileChooserParams?.createIntent(), CHOOSE_FILE_REQUEST_CODE
|
|
|
|
)
|
2025-03-18 14:16:12 +01:00
|
|
|
this@MainActivity.filePathCallback = filePathCallback
|
|
|
|
return true
|
2025-03-18 15:26:56 +01:00
|
|
|
} catch (e: Exception) {
|
|
|
|
Log.e("DL", "Error ${e.message}")
|
2025-03-18 14:16:12 +01:00
|
|
|
Toast.makeText(activity, "Error ${e.message}", Toast.LENGTH_LONG).show()
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
2025-03-17 11:50:13 +01:00
|
|
|
}
|
2025-03-18 14:16:12 +01:00
|
|
|
}
|
2025-03-17 11:50:13 +01:00
|
|
|
|
2025-03-18 14:16:12 +01:00
|
|
|
webView.setDownloadListener(DownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
|
2025-03-18 15:26:56 +01:00
|
|
|
downloadFile(url)
|
2025-03-17 11:50:13 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
2025-02-20 11:34:11 +01:00
|
|
|
|
2025-02-15 19:21:00 +01:00
|
|
|
setContentView(webView)
|
|
|
|
}
|
2025-03-18 15:26:56 +01:00
|
|
|
}
|