ToastCompatをソースツリーに取り込んでAndroid 11でも動作するよう変更
This commit is contained in:
parent
b822763151
commit
0134ccd465
|
@ -178,8 +178,6 @@ dependencies {
|
||||||
|
|
||||||
implementation 'com.google.android.exoplayer:exoplayer:2.10.4'
|
implementation 'com.google.android.exoplayer:exoplayer:2.10.4'
|
||||||
|
|
||||||
implementation 'me.drakeet.support:toastcompat:1.0.2'
|
|
||||||
|
|
||||||
implementation 'com.caverock:androidsvg-aar:1.4'
|
implementation 'com.caverock:androidsvg-aar:1.4'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package jp.juggler.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import me.drakeet.support.toast.BadTokenListener
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import me.drakeet.support.toast.ToastCompat
|
import me.drakeet.support.toast.ToastCompat
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ object ToastUtils {
|
||||||
try {
|
try {
|
||||||
val duration = if(bLong) Toast.LENGTH_LONG else Toast.LENGTH_SHORT
|
val duration = if(bLong) Toast.LENGTH_LONG else Toast.LENGTH_SHORT
|
||||||
val t = ToastCompat.makeText(context, message, duration)
|
val t = ToastCompat.makeText(context, message, duration)
|
||||||
t.setBadTokenListener {}
|
t.setBadTokenListener{ }
|
||||||
t.show()
|
t.show()
|
||||||
refToast = WeakReference(t)
|
refToast = WeakReference(t)
|
||||||
} catch(ex : Throwable) {
|
} catch(ex : Throwable) {
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package me.drakeet.support.toast
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author drakeet
|
||||||
|
*/
|
||||||
|
fun interface BadTokenListener {
|
||||||
|
fun onBadTokenCaught( toast : Toast)
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package me.drakeet.support.toast
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.Display
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.WindowManager
|
||||||
|
import android.view.WindowManager.BadTokenException
|
||||||
|
import android.widget.Toast
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author drakeet
|
||||||
|
*/
|
||||||
|
internal class SafeToastContext(base : Context, private val toast : Toast) : ContextWrapper(base) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "WindowManagerWrapper"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var badTokenListener : BadTokenListener? = null
|
||||||
|
|
||||||
|
fun setBadTokenListener(badTokenListener : BadTokenListener?) {
|
||||||
|
this.badTokenListener = badTokenListener
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getApplicationContext() : Context =
|
||||||
|
ApplicationContextWrapper(baseContext.applicationContext)
|
||||||
|
|
||||||
|
inner class ApplicationContextWrapper(base : Context) : ContextWrapper(base) {
|
||||||
|
|
||||||
|
override fun getSystemService(name : String) : Any? =
|
||||||
|
if(WINDOW_SERVICE == name) {
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
WindowManagerWrapper(baseContext.getSystemService(name) as WindowManager)
|
||||||
|
} else{
|
||||||
|
super.getSystemService(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class WindowManagerWrapper(private val base : WindowManager) : WindowManager {
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
override fun getDefaultDisplay() : Display? =
|
||||||
|
base.defaultDisplay
|
||||||
|
|
||||||
|
override fun removeViewImmediate(view : View) =
|
||||||
|
base.removeViewImmediate(view)
|
||||||
|
|
||||||
|
override fun updateViewLayout(view : View, params : ViewGroup.LayoutParams) =
|
||||||
|
base.updateViewLayout(view, params)
|
||||||
|
|
||||||
|
override fun removeView(view : View) =
|
||||||
|
base.removeView(view)
|
||||||
|
|
||||||
|
override fun addView(view : View, params : ViewGroup.LayoutParams) {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "WindowManager's addView(view, params) has been hooked.")
|
||||||
|
base.addView(view, params)
|
||||||
|
} catch(e : BadTokenException) {
|
||||||
|
e.message?.let { Log.i(TAG, it) }
|
||||||
|
badTokenListener?.onBadTokenCaught(toast)
|
||||||
|
} catch(throwable : Throwable) {
|
||||||
|
Log.e(TAG, "[addView]", throwable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
package me.drakeet.support.toast
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.os.Build
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
|
||||||
|
// original implementation is https://github.com/PureWriter/ToastCompat
|
||||||
|
// Android 11 でgetViewがnullを返すことが増えたので
|
||||||
|
/**
|
||||||
|
* @author drakeet
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Construct an empty Toast object. You must call [.setView] before you
|
||||||
|
* can call [.show].
|
||||||
|
*
|
||||||
|
* @param context The context to use. Usually your [android.app.Application]
|
||||||
|
* or [android.app.Activity] object.
|
||||||
|
* @param baseToast The base toast
|
||||||
|
*/
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
class ToastCompat(
|
||||||
|
context : Context,
|
||||||
|
private val baseToast : Toast
|
||||||
|
) : Toast(context) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a standard toast that just contains a text view.
|
||||||
|
*
|
||||||
|
* @param context The context to use. Usually your [android.app.Application]
|
||||||
|
* or [android.app.Activity] object.
|
||||||
|
* @param text The text to show. Can be formatted text.
|
||||||
|
* @param duration How long to display the message. Either [.LENGTH_SHORT] or
|
||||||
|
* [.LENGTH_LONG]
|
||||||
|
*/
|
||||||
|
@SuppressLint("ShowToast")
|
||||||
|
fun makeText(context : Context, text : CharSequence?, duration : Int) : ToastCompat {
|
||||||
|
// We cannot pass the SafeToastContext to Toast.makeText() because
|
||||||
|
// the View will unwrap the base context and we are in vain.
|
||||||
|
val toast = Toast.makeText(context, text, duration)
|
||||||
|
setContextCompat(toast.view) { SafeToastContext(context, toast) }
|
||||||
|
return ToastCompat(context, toast)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a standard toast that just contains a text view with the text from a resource.
|
||||||
|
*
|
||||||
|
* @param context The context to use. Usually your [android.app.Application]
|
||||||
|
* or [android.app.Activity] object.
|
||||||
|
* @param resId The resource id of the string resource to use. Can be formatted text.
|
||||||
|
* @param duration How long to display the message. Either [.LENGTH_SHORT] or
|
||||||
|
* [.LENGTH_LONG]
|
||||||
|
* @throws Resources.NotFoundException if the resource can't be found.
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
fun makeText(context : Context, @StringRes resId : Int, duration : Int) : Toast {
|
||||||
|
return makeText(context, context.resources.getText(resId), duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setContextCompat(view : View?, contextCreator : () -> Context) {
|
||||||
|
if(view != null && Build.VERSION.SDK_INT == 25) {
|
||||||
|
try {
|
||||||
|
val field = View::class.java.getDeclaredField("mContext")
|
||||||
|
field.isAccessible = true
|
||||||
|
field[view] = contextCreator()
|
||||||
|
} catch(throwable : Throwable) {
|
||||||
|
throwable.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBadTokenListener(listener : BadTokenListener?) : ToastCompat {
|
||||||
|
(baseToast.view?.context as? SafeToastContext)
|
||||||
|
?.setBadTokenListener(listener)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setView(view : View) {
|
||||||
|
baseToast.view = view
|
||||||
|
setContextCompat(baseToast.view) { SafeToastContext(view.context, this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getView() : View? = baseToast.view
|
||||||
|
|
||||||
|
override fun show() = baseToast.show()
|
||||||
|
|
||||||
|
override fun setDuration(duration : Int) {
|
||||||
|
baseToast.duration = duration
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setGravity(gravity : Int, xOffset : Int, yOffset : Int) =
|
||||||
|
baseToast.setGravity(gravity, xOffset, yOffset)
|
||||||
|
|
||||||
|
override fun setMargin(horizontalMargin : Float, verticalMargin : Float) =
|
||||||
|
baseToast.setMargin(horizontalMargin, verticalMargin)
|
||||||
|
|
||||||
|
override fun setText(resId : Int) =
|
||||||
|
baseToast.setText(resId)
|
||||||
|
|
||||||
|
override fun setText(s : CharSequence) =
|
||||||
|
baseToast.setText(s)
|
||||||
|
|
||||||
|
override fun getHorizontalMargin() : Float =
|
||||||
|
baseToast.horizontalMargin
|
||||||
|
|
||||||
|
override fun getVerticalMargin() : Float =
|
||||||
|
baseToast.verticalMargin
|
||||||
|
|
||||||
|
override fun getDuration() : Int =
|
||||||
|
baseToast.duration
|
||||||
|
|
||||||
|
override fun getGravity() : Int =
|
||||||
|
baseToast.gravity
|
||||||
|
|
||||||
|
override fun getXOffset() : Int =
|
||||||
|
baseToast.xOffset
|
||||||
|
|
||||||
|
override fun getYOffset() : Int =
|
||||||
|
baseToast.yOffset
|
||||||
|
}
|
Loading…
Reference in New Issue