add logging
This commit is contained in:
parent
16ee306864
commit
eea1b0d2f5
@ -31,7 +31,6 @@ tasks.register("genDocs") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk = 35
|
compileSdk = 35
|
||||||
buildToolsVersion = "35.0.0"
|
buildToolsVersion = "35.0.0"
|
||||||
@ -84,6 +83,7 @@ dependencies {
|
|||||||
implementation("io.coil-kt:coil-svg:2.7.0")
|
implementation("io.coil-kt:coil-svg:2.7.0")
|
||||||
implementation("androidx.gridlayout:gridlayout:1.0.0")
|
implementation("androidx.gridlayout:gridlayout:1.0.0")
|
||||||
implementation("io.noties.markwon:core:4.6.2")
|
implementation("io.noties.markwon:core:4.6.2")
|
||||||
|
implementation("com.elvishew:xlog:1.11.1")
|
||||||
androidTestImplementation("junit:junit:4.13.2")
|
androidTestImplementation("junit:junit:4.13.2")
|
||||||
androidTestImplementation("androidx.test:core:1.6.1")
|
androidTestImplementation("androidx.test:core:1.6.1")
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.2.1")
|
androidTestImplementation("androidx.test.ext:junit:1.2.1")
|
||||||
|
@ -28,6 +28,7 @@ import coil.decode.SvgDecoder
|
|||||||
import coil.decode.VideoFrameDecoder
|
import coil.decode.VideoFrameDecoder
|
||||||
import coil.imageLoader
|
import coil.imageLoader
|
||||||
import coil.load
|
import coil.load
|
||||||
|
import com.elvishew.xlog.XLog
|
||||||
import com.fredhappyface.ewesticker.adapter.StickerPackAdapter
|
import com.fredhappyface.ewesticker.adapter.StickerPackAdapter
|
||||||
import com.fredhappyface.ewesticker.model.StickerPack
|
import com.fredhappyface.ewesticker.model.StickerPack
|
||||||
import com.fredhappyface.ewesticker.utilities.Cache
|
import com.fredhappyface.ewesticker.utilities.Cache
|
||||||
@ -94,6 +95,10 @@ class ImageKeyboard : InputMethodService(), StickerClickListener {
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
// Misc
|
// Misc
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
XLog.i("=".repeat(80))
|
||||||
|
XLog.i("Loaded $packageName:${javaClass.name}")
|
||||||
|
|
||||||
val scale = baseContext.resources.displayMetrics.density
|
val scale = baseContext.resources.displayMetrics.density
|
||||||
// Setup coil
|
// Setup coil
|
||||||
val imageLoader =
|
val imageLoader =
|
||||||
@ -113,6 +118,10 @@ class ImageKeyboard : InputMethodService(), StickerClickListener {
|
|||||||
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(baseContext)
|
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(baseContext)
|
||||||
this.backupSharedPreferences =
|
this.backupSharedPreferences =
|
||||||
this.getSharedPreferences("backup_prefs", Context.MODE_PRIVATE)
|
this.getSharedPreferences("backup_prefs", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
XLog.i("Loading private shared preferences: ${this.sharedPreferences.all}")
|
||||||
|
XLog.i("Loading backup shared preferences: ${this.backupSharedPreferences.all}")
|
||||||
|
|
||||||
this.restoreOnClose = this.backupSharedPreferences.getBoolean("restoreOnClose", false)
|
this.restoreOnClose = this.backupSharedPreferences.getBoolean("restoreOnClose", false)
|
||||||
this.vertical = this.backupSharedPreferences.getBoolean("vertical", false)
|
this.vertical = this.backupSharedPreferences.getBoolean("vertical", false)
|
||||||
this.scroll = this.backupSharedPreferences.getBoolean("scroll", false)
|
this.scroll = this.backupSharedPreferences.getBoolean("scroll", false)
|
||||||
@ -147,6 +156,8 @@ class ImageKeyboard : InputMethodService(), StickerClickListener {
|
|||||||
}
|
}
|
||||||
this.allStickers += pack.stickerList
|
this.allStickers += pack.stickerList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XLog.i("Loaded all packs: [${this.loadedPacks.keys.joinToString(", ")}]")
|
||||||
this.activePack = this.sharedPreferences.getString("activePack", "").toString()
|
this.activePack = this.sharedPreferences.getString("activePack", "").toString()
|
||||||
// Caches
|
// Caches
|
||||||
this.sharedPreferences.getString("recentCache", "")?.let {
|
this.sharedPreferences.getString("recentCache", "")?.let {
|
||||||
@ -222,6 +233,7 @@ class ImageKeyboard : InputMethodService(), StickerClickListener {
|
|||||||
|
|
||||||
/** When leaving some input field update the caches */
|
/** When leaving some input field update the caches */
|
||||||
override fun onFinishInput() {
|
override fun onFinishInput() {
|
||||||
|
XLog.i("Updating sharedPreferences based on use, and closing...")
|
||||||
val editor = this.sharedPreferences.edit()
|
val editor = this.sharedPreferences.edit()
|
||||||
editor.putString("recentCache", this.recentCache.toSharedPref())
|
editor.putString("recentCache", this.recentCache.toSharedPref())
|
||||||
editor.putString("compatCache", this.compatCache.toSharedPref())
|
editor.putString("compatCache", this.compatCache.toSharedPref())
|
||||||
@ -240,6 +252,7 @@ class ImageKeyboard : InputMethodService(), StickerClickListener {
|
|||||||
* @param packName String
|
* @param packName String
|
||||||
*/
|
*/
|
||||||
private fun switchPackLayout(packName: String) {
|
private fun switchPackLayout(packName: String) {
|
||||||
|
XLog.i("Switching pack to '$packName'")
|
||||||
this.activePack = packName
|
this.activePack = packName
|
||||||
for (packCard in this.packsList) {
|
for (packCard in this.packsList) {
|
||||||
val packButton = packCard.findViewById<ImageButton>(R.id.stickerButton)
|
val packButton = packCard.findViewById<ImageButton>(R.id.stickerButton)
|
||||||
@ -280,6 +293,7 @@ class ImageKeyboard : InputMethodService(), StickerClickListener {
|
|||||||
* Set the current tab to the search page/ view
|
* Set the current tab to the search page/ view
|
||||||
*/
|
*/
|
||||||
private fun searchView() {
|
private fun searchView() {
|
||||||
|
XLog.i("Switching to search")
|
||||||
for (packCard in this.packsList) {
|
for (packCard in this.packsList) {
|
||||||
val packButton = packCard.findViewById<ImageButton>(R.id.stickerButton)
|
val packButton = packCard.findViewById<ImageButton>(R.id.stickerButton)
|
||||||
if (packButton.tag == "__search__") {
|
if (packButton.tag == "__search__") {
|
||||||
@ -454,9 +468,6 @@ class ImageKeyboard : InputMethodService(), StickerClickListener {
|
|||||||
this.loadedPacks.keys.sorted()
|
this.loadedPacks.keys.sorted()
|
||||||
}.toTypedArray()
|
}.toTypedArray()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (sortedPackName in sortedPackNames) {
|
for (sortedPackName in sortedPackNames) {
|
||||||
val packButton = addPackButton(sortedPackName)
|
val packButton = addPackButton(sortedPackName)
|
||||||
packButton.load(this.loadedPacks[sortedPackName]?.thumbSticker)
|
packButton.load(this.loadedPacks[sortedPackName]?.thumbSticker)
|
||||||
|
@ -17,12 +17,20 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.elvishew.xlog.LogConfiguration
|
||||||
|
import com.elvishew.xlog.LogLevel
|
||||||
|
import com.elvishew.xlog.XLog
|
||||||
|
import com.elvishew.xlog.printer.AndroidPrinter
|
||||||
|
import com.elvishew.xlog.printer.file.FilePrinter
|
||||||
|
import com.elvishew.xlog.printer.file.clean.FileLastModifiedCleanStrategy
|
||||||
|
import com.fredhappyface.ewesticker.utilities.StickerImporter
|
||||||
import com.fredhappyface.ewesticker.utilities.Toaster
|
import com.fredhappyface.ewesticker.utilities.Toaster
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.File
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
||||||
/** MainActivity class inherits from the AppCompatActivity class - provides the settings view */
|
/** MainActivity class inherits from the AppCompatActivity class - provides the settings view */
|
||||||
@ -43,6 +51,17 @@ class MainActivity : AppCompatActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
val logConfig = LogConfiguration.Builder().logLevel(LogLevel.ALL).tag("EweSticker").build()
|
||||||
|
val androidPrinter =
|
||||||
|
AndroidPrinter(true) // Printer that print the log using android.util.Log
|
||||||
|
val filePrinter = FilePrinter.Builder(
|
||||||
|
File(filesDir, "logs").path
|
||||||
|
).cleanStrategy(FileLastModifiedCleanStrategy(86_400_000)).build() // 1day
|
||||||
|
XLog.init(logConfig, androidPrinter, filePrinter)
|
||||||
|
|
||||||
|
XLog.i("=".repeat(80))
|
||||||
|
XLog.i("Loaded $packageName:$localClassName")
|
||||||
|
|
||||||
val markwon: Markwon = Markwon.create(this)
|
val markwon: Markwon = Markwon.create(this)
|
||||||
val featuresText = findViewById<TextView>(R.id.features_text)
|
val featuresText = findViewById<TextView>(R.id.features_text)
|
||||||
markwon.setMarkdown(featuresText, getString(R.string.features_text))
|
markwon.setMarkdown(featuresText, getString(R.string.features_text))
|
||||||
@ -54,6 +73,9 @@ class MainActivity : AppCompatActivity() {
|
|||||||
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
this.backupSharedPreferences =
|
this.backupSharedPreferences =
|
||||||
this.getSharedPreferences("backup_prefs", Context.MODE_PRIVATE)
|
this.getSharedPreferences("backup_prefs", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
XLog.i("Loading private shared preferences: ${this.sharedPreferences.all}")
|
||||||
|
XLog.i("Loading backup shared preferences: ${this.backupSharedPreferences.all}")
|
||||||
this.contextView = findViewById(R.id.activityMainRoot)
|
this.contextView = findViewById(R.id.activityMainRoot)
|
||||||
this.toaster = Toaster(baseContext)
|
this.toaster = Toaster(baseContext)
|
||||||
refreshStickerDirPath()
|
refreshStickerDirPath()
|
||||||
@ -71,12 +93,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
toggle(findViewById(R.id.insensitive_sort), "insensitiveSort", false) {}
|
toggle(findViewById(R.id.insensitive_sort), "insensitiveSort", false) {}
|
||||||
|
|
||||||
val versionText: TextView = findViewById(R.id.versionText)
|
val versionText: TextView = findViewById(R.id.versionText)
|
||||||
|
var version = getString(R.string.version_text)
|
||||||
try {
|
try {
|
||||||
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
||||||
versionText.text = packageInfo.versionName
|
version = packageInfo.versionName ?: version
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (_: PackageManager.NameNotFoundException) {
|
||||||
versionText.text = getString(R.string.version_text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
versionText.text = version
|
||||||
|
XLog.i("Version: $version")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,6 +133,22 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val saveFileLauncher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
if (result.resultCode == RESULT_OK) {
|
||||||
|
result.data?.data?.also { uri ->
|
||||||
|
val file = File(filesDir, "logs/log")
|
||||||
|
if (file.exists()) {
|
||||||
|
contentResolver.openOutputStream(uri)?.use { outputStream ->
|
||||||
|
file.inputStream().use { inputStream ->
|
||||||
|
inputStream.copyTo(outputStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called on button press to launch settings
|
* Called on button press to launch settings
|
||||||
*
|
*
|
||||||
@ -129,6 +171,20 @@ class MainActivity : AppCompatActivity() {
|
|||||||
chooseDirResultLauncher.launch(intent)
|
chooseDirResultLauncher.launch(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on button press to save logs
|
||||||
|
*
|
||||||
|
* @param ignoredView: View
|
||||||
|
*/
|
||||||
|
fun saveLogs(ignoredView: View) {
|
||||||
|
val saveIntent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "text/plain"
|
||||||
|
putExtra(Intent.EXTRA_TITLE, "ewesticker.log")
|
||||||
|
}
|
||||||
|
saveFileLauncher.launch(saveIntent)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reloadStickers
|
* reloadStickers
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package com.fredhappyface.ewesticker
|
package com.fredhappyface.ewesticker.utilities
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -6,8 +6,8 @@ import android.os.Handler
|
|||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import com.fredhappyface.ewesticker.utilities.Toaster
|
import com.elvishew.xlog.XLog
|
||||||
import com.fredhappyface.ewesticker.utilities.Utils
|
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
@ -28,6 +28,7 @@ private const val BUFFER_SIZE = 64 * 1024 // 64 KB
|
|||||||
* @property context: application baseContext
|
* @property context: application baseContext
|
||||||
* @property toaster: an instance of Toaster (used to store an error state for later reporting to the
|
* @property toaster: an instance of Toaster (used to store an error state for later reporting to the
|
||||||
* user)
|
* user)
|
||||||
|
* @property progressBar: LinearProgressIndicator that we update as we import stickers
|
||||||
*/
|
*/
|
||||||
class StickerImporter(
|
class StickerImporter(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@ -36,6 +37,7 @@ class StickerImporter(
|
|||||||
) {
|
) {
|
||||||
private val supportedMimes = Utils.getSupportedMimes()
|
private val supportedMimes = Utils.getSupportedMimes()
|
||||||
private val packSizes: MutableMap<String, Int> = mutableMapOf()
|
private val packSizes: MutableMap<String, Int> = mutableMapOf()
|
||||||
|
private var detectedStickers = 0
|
||||||
private var totalStickers = 0
|
private var totalStickers = 0
|
||||||
|
|
||||||
private val mainHandler = Handler(Looper.getMainLooper())
|
private val mainHandler = Handler(Looper.getMainLooper())
|
||||||
@ -53,14 +55,17 @@ class StickerImporter(
|
|||||||
* @param stickerDirPath a URI to the stickers directory to import into EweSticker
|
* @param stickerDirPath a URI to the stickers directory to import into EweSticker
|
||||||
*/
|
*/
|
||||||
suspend fun importStickers(stickerDirPath: String): Int {
|
suspend fun importStickers(stickerDirPath: String): Int {
|
||||||
|
XLog.i("Removing old stickers...")
|
||||||
File(context.filesDir, "stickers").deleteRecursively()
|
File(context.filesDir, "stickers").deleteRecursively()
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
progressBar.visibility = View.VISIBLE
|
progressBar.visibility = View.VISIBLE
|
||||||
progressBar.isIndeterminate = true
|
progressBar.isIndeterminate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XLog.i("Walking $stickerDirPath...")
|
||||||
val leafNodes = fileWalk(DocumentFile.fromTreeUri(context, Uri.parse(stickerDirPath)))
|
val leafNodes = fileWalk(DocumentFile.fromTreeUri(context, Uri.parse(stickerDirPath)))
|
||||||
if (leafNodes.size > MAX_FILES) {
|
if (leafNodes.size > MAX_FILES) {
|
||||||
|
XLog.w("Found more than $MAX_FILES stickers, notify user")
|
||||||
toaster.setState(1)
|
toaster.setState(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +74,7 @@ class StickerImporter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform concurrent file copy operations
|
// Perform concurrent file copy operations
|
||||||
|
XLog.i("Perform concurrent file copy operations...")
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
leafNodes.take(MAX_FILES).mapIndexed { index, file ->
|
leafNodes.take(MAX_FILES).mapIndexed { index, file ->
|
||||||
async {
|
async {
|
||||||
@ -84,7 +90,9 @@ class StickerImporter(
|
|||||||
progressBar.visibility = View.GONE
|
progressBar.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
return leafNodes.size
|
XLog.i("Copied $totalStickers / $detectedStickers")
|
||||||
|
|
||||||
|
return totalStickers
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,10 +106,12 @@ class StickerImporter(
|
|||||||
val parentDir = sticker.parentFile?.name ?: "__default__"
|
val parentDir = sticker.parentFile?.name ?: "__default__"
|
||||||
val packSize = packSizes[parentDir] ?: 0
|
val packSize = packSizes[parentDir] ?: 0
|
||||||
if (packSize > MAX_PACK_SIZE) {
|
if (packSize > MAX_PACK_SIZE) {
|
||||||
|
XLog.w("Found more than $MAX_PACK_SIZE stickers in '$parentDir', notify user")
|
||||||
toaster.setState(2)
|
toaster.setState(2)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (sticker.type !in supportedMimes) {
|
if (sticker.type !in supportedMimes) {
|
||||||
|
XLog.w("'$parentDir/${sticker.name}' is not a supported mimetype (${sticker.type}), notify user")
|
||||||
toaster.setState(3)
|
toaster.setState(3)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -126,7 +136,9 @@ class StickerImporter(
|
|||||||
}
|
}
|
||||||
totalStickers++
|
totalStickers++
|
||||||
}
|
}
|
||||||
} catch (_: IOException) {
|
} catch (e: IOException) {
|
||||||
|
XLog.e("There was an IOException when copying '${parentDir}/${sticker.name}'!")
|
||||||
|
XLog.e(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,9 +160,10 @@ class StickerImporter(
|
|||||||
currentFile?.listFiles()?.forEach { file ->
|
currentFile?.listFiles()?.forEach { file ->
|
||||||
if (file.isFile) {
|
if (file.isFile) {
|
||||||
leafNodes.add(file)
|
leafNodes.add(file)
|
||||||
totalStickers++
|
detectedStickers++
|
||||||
|
|
||||||
if (leafNodes.size >= MAX_FILES) {
|
if (leafNodes.size > MAX_FILES + 1) {
|
||||||
|
XLog.w("Found more than ${MAX_FILES + 1} stickers, so returning early")
|
||||||
return leafNodes
|
return leafNodes
|
||||||
}
|
}
|
||||||
} else if (file.isDirectory) {
|
} else if (file.isDirectory) {
|
@ -4,7 +4,6 @@ import android.content.ClipDescription
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.util.Log
|
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputConnection
|
import android.view.inputmethod.InputConnection
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
@ -13,6 +12,7 @@ import androidx.core.view.inputmethod.InputConnectionCompat
|
|||||||
import androidx.core.view.inputmethod.InputContentInfoCompat
|
import androidx.core.view.inputmethod.InputContentInfoCompat
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
|
import com.elvishew.xlog.XLog
|
||||||
import com.fredhappyface.ewesticker.R
|
import com.fredhappyface.ewesticker.R
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -50,6 +50,15 @@ class StickerSender(
|
|||||||
private val supportedMimes = this.currentInputEditorInfo?.contentMimeTypes ?: emptyArray()
|
private val supportedMimes = this.currentInputEditorInfo?.contentMimeTypes ?: emptyArray()
|
||||||
private val packageName = this.currentInputEditorInfo?.packageName
|
private val packageName = this.currentInputEditorInfo?.packageName
|
||||||
|
|
||||||
|
init {
|
||||||
|
XLog.i("Connecting to $packageName which supports [${supportedMimes.joinToString(", ")}]")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper function to display a toast message to the user
|
||||||
|
*
|
||||||
|
* @param message String
|
||||||
|
*/
|
||||||
private fun showToast(message: String) {
|
private fun showToast(message: String) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
toaster.toast(message)
|
toaster.toast(message)
|
||||||
@ -68,6 +77,8 @@ class StickerSender(
|
|||||||
val compatSticker = File(internalDir, "__compatSticker__/$compatStickerName.png")
|
val compatSticker = File(internalDir, "__compatSticker__/$compatStickerName.png")
|
||||||
|
|
||||||
if (!compatSticker.exists()) {
|
if (!compatSticker.exists()) {
|
||||||
|
XLog.i("Create a fallback png sticker '__compatSticker__/$compatStickerName.png'")
|
||||||
|
|
||||||
compatSticker.parentFile?.mkdirs()
|
compatSticker.parentFile?.mkdirs()
|
||||||
try {
|
try {
|
||||||
val request = ImageRequest.Builder(context)
|
val request = ImageRequest.Builder(context)
|
||||||
@ -95,6 +106,11 @@ class StickerSender(
|
|||||||
return compatSticker
|
return compatSticker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main method to send a sticker to an InputConnectionCompat, this attempts to send via the happy path (assuming the
|
||||||
|
* InputConnectionCompat supports the stickers mime type. Otherwise attempts falling back to png, and then finally if that fails,
|
||||||
|
* opening a share sheet
|
||||||
|
*/
|
||||||
fun sendSticker(file: File) {
|
fun sendSticker(file: File) {
|
||||||
val stickerType = Utils.getMimeType(file) ?: "__unknown__"
|
val stickerType = Utils.getMimeType(file) ?: "__unknown__"
|
||||||
|
|
||||||
@ -105,63 +121,28 @@ class StickerSender(
|
|||||||
|| "video/*" in supportedMimes && stickerType.startsWith("video/"))
|
|| "video/*" in supportedMimes && stickerType.startsWith("video/"))
|
||||||
&& stickerType != "image/svg+xml"
|
&& stickerType != "image/svg+xml"
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if (!doCommitContent(stickerType, file)) {
|
if (!doCommitContent(stickerType, file)) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
doFallbackCommitContent(file)
|
doFallbackCommitContent(stickerType, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
doFallbackCommitContent(file)
|
doFallbackCommitContent(stickerType, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openShareSheet(file: File) {
|
|
||||||
val uri = FileProvider.getUriForFile(
|
|
||||||
context,
|
|
||||||
"com.fredhappyface.ewesticker.inputcontent",
|
|
||||||
file,
|
|
||||||
)
|
|
||||||
|
|
||||||
val shareIntent = Intent().apply {
|
|
||||||
action = Intent.ACTION_SEND
|
|
||||||
putExtra(Intent.EXTRA_STREAM, uri)
|
|
||||||
type = "image/*"
|
|
||||||
}
|
|
||||||
|
|
||||||
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
|
|
||||||
val chooserIntent = Intent.createChooser(shareIntent, "Share Sticker")
|
|
||||||
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
context.startActivity(chooserIntent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun doFallbackCommitContent(file: File) {
|
|
||||||
|
|
||||||
if ("image/png" in supportedMimes || "image/*" in supportedMimes) {
|
|
||||||
val compatSticker = createCompatSticker(file)
|
|
||||||
if (compatSticker != null) {
|
|
||||||
if (!doCommitContent("image/png", compatSticker)) {
|
|
||||||
openShareSheet(file)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
openShareSheet(file)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a sticker file to a InputConnectionCompat
|
* Called by sendSticker. Send a sticker file to a InputConnectionCompat
|
||||||
*
|
*
|
||||||
* @param mimeType String
|
* @param mimeType String
|
||||||
* @param file File
|
* @param file File
|
||||||
|
* @return success Boolean
|
||||||
*/
|
*/
|
||||||
private fun doCommitContent(mimeType: String, file: File): Boolean {
|
private fun doCommitContent(mimeType: String, file: File): Boolean {
|
||||||
// Log.d("QWERTY", "Sending ${file.name} ($mimeType) to ${this.packageName}")
|
XLog.i("Sending ${file.name} ($mimeType) to ${this.packageName}")
|
||||||
val inputContentInfoCompat = InputContentInfoCompat(
|
val inputContentInfoCompat = InputContentInfoCompat(
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
context,
|
context,
|
||||||
@ -185,4 +166,53 @@ class StickerSender(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by sendSticker. Otherwise attempts falling back to png, and then finally if that fails, opening a
|
||||||
|
* share sheet to send the sticker
|
||||||
|
*
|
||||||
|
* @param mimeType String
|
||||||
|
* @param file File
|
||||||
|
*/
|
||||||
|
private suspend fun doFallbackCommitContent(mimeType: String, file: File) {
|
||||||
|
|
||||||
|
if ("image/png" in supportedMimes || "image/*" in supportedMimes) {
|
||||||
|
val compatSticker = createCompatSticker(file)
|
||||||
|
if (compatSticker != null) {
|
||||||
|
if (!doCommitContent("image/png", compatSticker)) {
|
||||||
|
openShareSheet(mimeType, file)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
openShareSheet(mimeType, file)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by doFallbackCommitContent. Opens a share sheet to send the sticker
|
||||||
|
*
|
||||||
|
* @param mimeType String
|
||||||
|
* @param file File
|
||||||
|
*/
|
||||||
|
private fun openShareSheet(mimeType: String, file: File) {
|
||||||
|
XLog.i("$packageName reports that is doesn't support png over its InputConnectionCompat, so open a share sheet")
|
||||||
|
val uri = FileProvider.getUriForFile(
|
||||||
|
context,
|
||||||
|
"com.fredhappyface.ewesticker.inputcontent",
|
||||||
|
file,
|
||||||
|
)
|
||||||
|
|
||||||
|
val shareIntent = Intent().apply {
|
||||||
|
action = Intent.ACTION_SEND
|
||||||
|
putExtra(Intent.EXTRA_STREAM, uri)
|
||||||
|
type = mimeType
|
||||||
|
}
|
||||||
|
|
||||||
|
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
|
||||||
|
val chooserIntent = Intent.createChooser(shareIntent, "Share Sticker")
|
||||||
|
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
context.startActivity(chooserIntent)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -405,6 +405,25 @@
|
|||||||
android:text="@string/version_text" />
|
android:text="@string/version_text" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
<!-- Logs -->
|
||||||
|
<com.google.android.material.card.MaterialCardView style="@style/card">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/cardchild"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/heading"
|
||||||
|
android:text="@string/logs_heading" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="@style/button"
|
||||||
|
android:onClick="saveLogs"
|
||||||
|
android:text="@string/logs_button"
|
||||||
|
app:shapeAppearance="?attr/shapeAppearanceSmallComponent" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
android:layout_height="@dimen/qwerty_row_height"
|
android:layout_height="@dimen/qwerty_row_height"
|
||||||
android:id="@+id/search_text"/>
|
android:id="@+id/search_text"/>
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -51,8 +50,6 @@
|
|||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -63,10 +60,6 @@
|
|||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
<dimen name="text_size_tiny">10sp</dimen>
|
<dimen name="text_size_tiny">10sp</dimen>
|
||||||
<dimen name="qwerty_row_height">40sp</dimen>
|
<dimen name="qwerty_row_height">40sp</dimen>
|
||||||
|
|
||||||
|
|
||||||
<dimen name="content_margin">10dp</dimen>
|
<dimen name="content_margin">10dp</dimen>
|
||||||
<dimen name="card_margin">16dp</dimen>
|
<dimen name="card_margin">16dp</dimen>
|
||||||
<dimen name="content_margin_top">8dp</dimen>
|
<dimen name="content_margin_top">8dp</dimen>
|
||||||
|
@ -70,7 +70,9 @@ Copyright © Randy Zhou</string>
|
|||||||
(See the license for more information https://github.com/FredHappyface/Android.EweSticker/blob/main/LICENSE.md )</string>
|
(See the license for more information https://github.com/FredHappyface/Android.EweSticker/blob/main/LICENSE.md )</string>
|
||||||
<string name="version_heading">Version Info</string>
|
<string name="version_heading">Version Info</string>
|
||||||
<string name="version_text" translatable="false">[debug]</string>
|
<string name="version_text" translatable="false">[debug]</string>
|
||||||
|
<!-- Logs -->
|
||||||
|
<string name="logs_heading">Logs</string>
|
||||||
|
<string name="logs_button">Get log file</string>
|
||||||
<!-- Interactive Messages -->
|
<!-- Interactive Messages -->
|
||||||
<string name="pref_000">Preferences changed. Reload the keyboard for settings to apply</string>
|
<string name="pref_000">Preferences changed. Reload the keyboard for settings to apply</string>
|
||||||
<string name="imported_010">Starting import. This might take some time!</string>
|
<string name="imported_010">Starting import. This might take some time!</string>
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
<item name="android:background">@drawable/qwerty_key</item>
|
<item name="android:background">@drawable/qwerty_key</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<style name="ToolbarTitleTextAppearance" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
|
<style name="ToolbarTitleTextAppearance" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
|
||||||
<item name="android:textSize">@dimen/text_size_title</item>
|
<item name="android:textSize">@dimen/text_size_title</item>
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user