Fix media gallery activity

Summary:
Weird edge case, this activity doesnt actualy contain the content and instead its in the decor view behind it, solution is to filter it out from traversal and snapshot

https://fb.workplace.com/groups/443457641253219/permalink/643518977913750/

Reviewed By: elboman, lblasa

Differential Revision: D50936817

fbshipit-source-id: 8c1e276d4d943c42c9c2085bf70113347cbd5c74
This commit is contained in:
Luke De Feo
2023-11-02 12:29:07 -07:00
committed by Facebook GitHub Bot
parent 62e9181075
commit 3bb3ce6a66
5 changed files with 42 additions and 12 deletions

View File

@@ -12,6 +12,7 @@ import android.app.Activity
import android.app.Application import android.app.Application
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.lang.reflect.Field import java.lang.reflect.Field
import java.lang.reflect.Method import java.lang.reflect.Method
@@ -103,6 +104,11 @@ object ActivityTracker : Application.ActivityLifecycleCallbacks {
return stack return stack
} }
val decorViewToActivityMap: Map<View, Activity>
get() {
return activitiesStack.toList().associateBy { it.window.decorView }
}
/** /**
* Activity tracker is used to track activities. However, it cannot track via life-cycle events * Activity tracker is used to track activities. However, it cannot track via life-cycle events
* all those activities that were created prior to initialisation via the `start(application: * all those activities that were created prior to initialisation via the `start(application:

View File

@@ -9,6 +9,7 @@ package com.facebook.flipper.plugins.uidebugger.core
import android.app.Activity import android.app.Activity
import android.app.Application import android.app.Application
import android.view.View
class ApplicationRef(val application: Application) { class ApplicationRef(val application: Application) {
init { init {

View File

@@ -7,6 +7,7 @@
package com.facebook.flipper.plugins.uidebugger.core package com.facebook.flipper.plugins.uidebugger.core
import android.app.Activity
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
@@ -58,7 +59,14 @@ class DecorViewTracker(private val context: UIDContext, private val snapshotter:
currentDecorView?.viewTreeObserver?.removeOnPreDrawListener(preDrawListener) currentDecorView?.viewTreeObserver?.removeOnPreDrawListener(preDrawListener)
// setup new listener on top most view, that will be the active child in traversal // setup new listener on top most view, that will be the active child in traversal
val topView = rootViews.lastOrNull(ApplicationRefDescriptor::isUsefulRoot)
val decorViewToActivity: Map<View, Activity> = ActivityTracker.decorViewToActivityMap
val topView =
rootViews.lastOrNull { view ->
val activityOrView = decorViewToActivity[view] ?: view
ApplicationRefDescriptor.isUsefulRoot(activityOrView)
}
if (topView != null) { if (topView != null) {
val throttler = val throttler =

View File

@@ -104,8 +104,8 @@ class PixelCopySnapshotter(
bitmap: BitmapPool.ReusableBitmap bitmap: BitmapPool.ReusableBitmap
): Boolean { ): Boolean {
val decorViewToActivity: Map<View, Activity> =
applicationRef.activitiesStack.toList().associateBy { it.window.decorView } val decorViewToActivity: Map<View, Activity> = ActivityTracker.decorViewToActivityMap
val activityForDecorView = decorViewToActivity[view] ?: return false val activityForDecorView = decorViewToActivity[view] ?: return false

View File

@@ -10,6 +10,7 @@ package com.facebook.flipper.plugins.uidebugger.descriptors
import android.app.Activity import android.app.Activity
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.facebook.flipper.plugins.uidebugger.core.ActivityTracker
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
import com.facebook.flipper.plugins.uidebugger.model.Bounds import com.facebook.flipper.plugins.uidebugger.model.Bounds
import com.facebook.flipper.plugins.uidebugger.util.DisplayMetrics import com.facebook.flipper.plugins.uidebugger.util.DisplayMetrics
@@ -33,12 +34,11 @@ object ApplicationRefDescriptor : ChainedDescriptor<ApplicationRef>() {
override fun onGetChildren(node: ApplicationRef): List<Any> { override fun onGetChildren(node: ApplicationRef): List<Any> {
val children = mutableListOf<Any>() val children = mutableListOf<Any>()
val activeRoots = node.rootsResolver.rootViews() val rootViews = node.rootsResolver.rootViews()
val decorViewToActivity: Map<View, Activity> = val decorViewToActivity: Map<View, Activity> = ActivityTracker.decorViewToActivityMap
node.activitiesStack.toList().associateBy { it.window.decorView }
for (root in activeRoots) { for (root in rootViews) {
// if there is an activity for this root view use that, // if there is an activity for this root view use that,
// if not just return the root view that was added directly to the window manager // if not just return the root view that was added directly to the window manager
val activity = decorViewToActivity[root] val activity = decorViewToActivity[root]
@@ -52,16 +52,31 @@ object ApplicationRefDescriptor : ChainedDescriptor<ApplicationRef>() {
return children return children
} }
fun isUsefulRoot(obj: Any): Boolean { /**
if (obj is Activity) { * arg is either an acitivity if the root view has one other views the root view attached to the
* window manager returns boolean indicating whether we are interested in it and whether we should
* track, traverse and snapshot it
*/
fun isUsefulRoot(rootViewOrActivity: Any): Boolean {
val className = rootViewOrActivity.javaClass.name
if (className.contains("mediagallery.ui.MediaGalleryActivity")) {
// this activity doesn't contain the content and its actually in the decor view behind it, so
// skip it :/
return false
}
if (rootViewOrActivity is Activity) {
// in general we want views attached to activities
return true return true
} }
val isFoldableOverlayInfraView = javaClass.simpleName.contains("OverlayHandlerView")
val isFoldableOverlayInfraView = className.contains("OverlayHandlerView")
return if (isFoldableOverlayInfraView) { return if (isFoldableOverlayInfraView) {
false false
} else if (obj is ViewGroup) { } else if (rootViewOrActivity is ViewGroup) {
// sometimes there is a root view on top that has no children that isn't useful to inspect // sometimes there is a root view on top that has no children that isn't useful to inspect
obj.childCount > 0 rootViewOrActivity.childCount > 0
} else { } else {
false false
} }