SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/util/CustomShare.kt

193 lines
6.4 KiB
Kotlin

package jp.juggler.subwaytooter.util
import android.content.*
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.Pref
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.util.LogCategory
import jp.juggler.util.attrColor
import jp.juggler.util.showToast
import jp.juggler.util.systemService
enum class CustomShareTarget {
Translate,
CustomShare1,
CustomShare2,
CustomShare3,
}
object CustomShare {
val log = LogCategory("CustomShare")
const val CN_CLIPBOARD = "<InApp>/CopyToClipboard"
private const val translate_app_component_default =
"com.google.android.apps.translate/com.google.android.apps.translate.TranslateActivity"
fun getCustomShareComponentName(
pref: SharedPreferences,
target: CustomShareTarget
): ComponentName? {
val src: String
val defaultComponentName: String?
when (target) {
CustomShareTarget.Translate -> {
src = Pref.spTranslateAppComponent(pref)
defaultComponentName = translate_app_component_default
}
CustomShareTarget.CustomShare1 -> {
src = Pref.spCustomShare1(pref)
defaultComponentName = null
}
CustomShareTarget.CustomShare2 -> {
src = Pref.spCustomShare2(pref)
defaultComponentName = null
}
CustomShareTarget.CustomShare3 -> {
src = Pref.spCustomShare3(pref)
defaultComponentName = null
}
}
return src.cn() ?: defaultComponentName?.cn()
}
fun getInfo(context: Context, cn: ComponentName?): Pair<CharSequence?, Drawable?> {
var label: CharSequence? = null
var icon: Drawable? = null
try {
if (cn != null) {
val cnStr = "${cn.packageName}/${cn.className}"
label = cnStr
if (cnStr == CN_CLIPBOARD) {
label =
"${context.getString(R.string.copy_to_clipboard)}(${context.getString(R.string.app_name)})"
icon = ContextCompat.getDrawable(context, R.drawable.ic_copy)?.mutate()?.apply {
setTint(context.attrColor(R.attr.colorVectorDrawable))
setTintMode(PorterDuff.Mode.SRC_IN)
}
} else {
val pm = context.packageManager
val ri = pm.resolveActivity(Intent().apply { component = cn }, 0)
if (ri != null) {
try {
label = ri.loadLabel(pm)
} catch (ex: Throwable) {
log.e(ex, "loadLabel failed.")
}
try {
icon = ri.loadIcon(pm)
} catch (ex: Throwable) {
log.e(ex, "loadIcon failed.")
}
}
}
}
} catch (ex: Throwable) {
log.e(ex, "getInfo failed.")
}
return Pair(label, icon)
}
fun invoke(
context: Context,
text: String,
target: CustomShareTarget
) {
// convert "pkgName/className" string to ComponentName object.
val cn = getCustomShareComponentName(App1.pref, target)
if (cn == null) {
context.showToast(true, R.string.custom_share_app_not_found)
return
}
val cnStr = "${cn.packageName}/${cn.className}"
if (cnStr == CN_CLIPBOARD) {
try {
val cm: ClipboardManager = systemService(context)!!
cm.setPrimaryClip(ClipData.newPlainText("", text))
context.showToast(false, R.string.copied_to_clipboard)
} catch (ex: Throwable) {
context.showToast(ex, "copy to clipboard failed.")
}
return
}
try {
val intent = Intent()
intent.action = Intent.ACTION_SEND
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, text)
intent.component = cn
context.startActivity(intent)
} catch (ex: ActivityNotFoundException) {
log.trace(ex)
context.showToast(true, R.string.custom_share_app_not_found)
} catch (ex: Throwable) {
log.trace(ex)
context.showToast(ex, "invoke() failed.")
}
}
fun invoke(
context: Context,
access_info: SavedAccount,
status: TootStatus?,
target: CustomShareTarget
) {
status ?: return
try {
// convert "pkgName/className" string to ComponentName object.
val cn = getCustomShareComponentName(App1.pref, target)
if (cn == null) {
context.showToast(true, R.string.custom_share_app_not_found)
return
}
val sv = TootTextEncoder.encodeStatusForTranslate(context, access_info, status)
invoke(context, sv, target)
} catch (ex: Throwable) {
log.trace(ex)
context.showToast(ex, "invoke() failed.")
}
}
private val cache = HashMap<CustomShareTarget, Pair<CharSequence?, Drawable?>>()
fun getCache(target: CustomShareTarget) = cache[target]
fun reloadCache(context: Context, pref: SharedPreferences) {
CustomShareTarget.values().forEach { target ->
val cn = getCustomShareComponentName(pref, target)
val pair = getInfo(context, cn)
cache[target] = pair
}
}
}
// convert "pkgName/className" string to ComponentName object.
fun String.cn(): ComponentName? {
try {
val idx = indexOf('/')
if (idx >= 1) return ComponentName(substring(0 until idx), substring(idx + 1))
} catch (ex: Throwable) {
CustomShare.log.e(ex, "incorrect component name $this")
}
return null
}
fun ComponentName.exists(context: Context): Boolean {
return try {
context.packageManager.resolveActivity(Intent().apply { component = this@exists }, 0)
?.activityInfo?.exported ?: false
} catch (_: Throwable) {
false
}
}