本文最后更新于 880 天前,其中的信息可能已经有所发展或是发生改变。
- Activity 在 attach 阶段创建了 PhoneWindow,并将 AppToken 存储到 PhoneWindow 中,然后通过 createLocalWindowManager 创建了一个本地的 WindowManager,该实例是 WindowManagerImpl,构造传入的 parentWindow 为 PhoneWindow。在 onResume 阶段时,从 PhoneWindow 中获取 WindowManager 来 addView。
-
Dialog 有自己的 PhoneWindow,但 Dialog 并没有从 PhoneWindow 中去 get WindowManager,而是直接使用 getSystemService 拿到 Activity 的 WindowManager 来 addView。
-
PopWindow 内部是通过 getSystemService 来拿到 Activity WindowManager + 内置子窗口 type 来实现的弹框。
internal class FloatingActivityLifecycle : Application.ActivityLifecycleCallbacks {
private val mActivities = ArrayList<Activity>()
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
mActivities.add(activity)
}
override fun onActivityStarted(activity: Activity) {
}
override fun onActivityResumed(activity: Activity) {
}
override fun onActivityPaused(activity: Activity) {
}
override fun onActivityStopped(activity: Activity) {
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}
override fun onActivityDestroyed(activity: Activity) {
mActivities.remove(activity)
}
fun getActivities(): List<Activity> {
return mActivities.toList()
}
}
object FloatingWindowManager {
private val lifecycle by lazy {
FloatingActivityLifecycle()
}
@JvmStatic
fun init(context: Application) {
context.registerActivityLifecycleCallbacks(lifecycle)
}
/**
* WindowManagerGlobal mViews:
*
* 0、Ac:------
* 1、-- Dialog
* 2、-- Dialog
* 3、Ac:------
* 4、Ac:------
*/
fun hasFloatingWindowByView(activity: Activity): Boolean {
return getFloatWindowViewByView(activity).isNotEmpty()
}
fun getFloatWindowViewByView(activity: Activity): List<View> {
val targetDecorView = activity.window.decorView
val acDecorViews = lifecycle.getActivities().map { it.window.decorView }.toList()
val mView = Window.getViews().map { it }.toList()
val targetIndex = mView.first { it == targetDecorView }
val index = mView.indexOf(targetIndex)
val floatView = arrayListOf<View>()
for (i in index + 1 until mView.size) {
if (acDecorViews.contains(mView[i])) {
break
}
floatView.add(mView[i])
}
return floatView
}
fun hasFloatWindowByToken(activity: Activity): Boolean {
// 获取目标 Activity 的 decorView
val targetDecorView = activity.window.decorView
// 获取目标 Activity 的 子窗口的 token
val targetSubToken = targetDecorView.windowToken
// 拿到 mView 集合,找到目标 Activity 所在的 index 位置
val mView = Window.getViews().map { it }.toList()
val targetIndex = mView.indexOfFirst { it == targetDecorView }
// 获取 mParams 集合
val mParams = Window.getParams()
// 根据目标 index 从 mParams 集合中找到目标 token
val targetToken = mParams[targetIndex].token
// 遍历判断时,目标 Activity 自己不能包括,所以 size 需要大于 1
return mParams
.map { it.token }
.filter { it == targetSubToken || it == null || it == targetToken }
.size > 1
}
fun getFloatWindowViewByToken(activity: Activity): List<View> {
// 获取目标 Activity 的 decorView
val targetDecorView = activity.window.decorView
// 获取目标 Activity 的 子窗口的 token
val targetSubToken = targetDecorView.windowToken
// 拿到 mView 集合,找到目标 Activity 所在的 index 位置
val mView = Window.getViews().map { it }.toList()
val targetIndex = mView.indexOfFirst { it == targetDecorView }
// 获取 mParams 集合
val mParams = Window.getParams()
// 根据目标 index 从 mParams 集合中找到目标 token
val targetToken = mParams[targetIndex].token
val floatView = arrayListOf<View>()
mParams.forEachIndexed { index, params ->
val token = params.token
// Activity 自身不参与
if (index != targetIndex) {
if (token == targetSubToken || token == null || token == targetToken) {
// 根据 index 拿到 mView 中的 View
floatView.add(mView[index])
}
}
}
return floatView
}
}
internal object Window {
private val windowManagerClass by lazy(LazyThreadSafetyMode.NONE) {
val className =
"android.view.WindowManagerGlobal"
try {
Class.forName(className)
} catch (ignored: Throwable) {
Log.w("WindowManagerSpy", ignored)
null
}
}
private val windowManagerInstance by lazy(LazyThreadSafetyMode.NONE) {
windowManagerClass?.let { windowManagerClass ->
val methodName =
"getInstance"
windowManagerClass.getMethod(methodName).invoke(null)
}
}
private val mViewsField by lazy(LazyThreadSafetyMode.NONE) {
windowManagerClass?.let { windowManagerClass ->
windowManagerClass.getDeclaredField("mViews").apply { isAccessible = true }
}
}
private val mParams by lazy(LazyThreadSafetyMode.NONE) {
windowManagerClass?.let { windowManagerClass ->
windowManagerClass.getDeclaredField("mParams").apply { isAccessible = true }
}
}
@SuppressLint("PrivateApi", "ObsoleteSdkInt", "DiscouragedPrivateApi")
fun getViews(): List<View> {
try {
windowManagerInstance?.let { windowManagerInstance ->
mViewsField?.let { mViewsField ->
return mViewsField[windowManagerInstance] as ArrayList<View>
}
}
} catch (ignored: Throwable) {
Log.w("WindowManagerSpy", ignored)
}
return arrayListOf()
}
@SuppressLint("PrivateApi", "ObsoleteSdkInt", "DiscouragedPrivateApi")
fun getParams(): List<WindowManager.LayoutParams> {
try {
windowManagerInstance?.let { windowManagerInstance ->
mParams?.let { mViewsField ->
return mViewsField[windowManagerInstance] as ArrayList<WindowManager.LayoutParams>
}
}
} catch (ignored: Throwable) {
Log.w("WindowManagerSpy", ignored)
}
return arrayListOf()
}
}