RootViewWatcher.kt
TLDR
The RootViewWatcher
class is a part of the LeakCanary library and is used to track root views and expect them to become weakly reachable after they are removed from the window manager.
Classes
RootViewWatcher
The RootViewWatcher
class implements the InstallableWatcher
interface and is responsible for tracking root views. It has the following properties and methods:
-
reachabilityWatcher
: This property holds an instance of theReachabilityWatcher
interface. -
listener
: This property holds an instance of theOnRootViewAddedListener
interface. -
install()
: This method installs theRootViewWatcher
instance by adding thelistener
to theonRootViewsChangedListeners
list in theCurtains
class. -
uninstall()
: This method uninstalls theRootViewWatcher
instance by removing thelistener
from theonRootViewsChangedListeners
list in theCurtains
class.
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package leakcanary
import android.app.Activity
import android.app.Dialog
import android.view.View
import android.view.View.OnAttachStateChangeListener
import com.squareup.leakcanary.objectwatcher.core.R
import curtains.Curtains
import curtains.OnRootViewAddedListener
import curtains.WindowType.PHONE_WINDOW
import curtains.WindowType.POPUP_WINDOW
import curtains.WindowType.TOAST
import curtains.WindowType.TOOLTIP
import curtains.WindowType.UNKNOWN
import curtains.phoneWindow
import curtains.windowType
import curtains.wrappedCallback
import leakcanary.internal.friendly.mainHandler
/**
* Expects root views to become weakly reachable soon after they are removed from the window
* manager.
*/
class RootViewWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val listener = OnRootViewAddedListener { rootView ->
val trackDetached = when(rootView.windowType) {
PHONE_WINDOW -> {
when (rootView.phoneWindow?.callback?.wrappedCallback) {
// Activities are already tracked by ActivityWatcher
is Activity -> false
is Dialog -> {
// Use app context resources to avoid NotFoundException
// https://github.com/square/leakcanary/issues/2137
val resources = rootView.context.applicationContext.resources
resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs)
}
// Probably a DreamService
else -> true
}
}
// Android widgets keep detached popup window instances around.
POPUP_WINDOW -> false
TOOLTIP, TOAST, UNKNOWN -> true
}
if (trackDetached) {
rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
val watchDetachedView = Runnable {
reachabilityWatcher.expectWeaklyReachable(
rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"
)
}
override fun onViewAttachedToWindow(v: View) {
mainHandler.removeCallbacks(watchDetachedView)
}
override fun onViewDetachedFromWindow(v: View) {
mainHandler.post(watchDetachedView)
}
})
}
}
override fun install() {
Curtains.onRootViewsChangedListeners += listener
}
override fun uninstall() {
Curtains.onRootViewsChangedListeners -= listener
}
}