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 = "/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 { 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>() 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 } }