Skip to content
This repository has been archived by the owner on Nov 22, 2024. It is now read-only.

Commit

Permalink
ApplicationRef
Browse files Browse the repository at this point in the history
Summary:
Introduce ApplicationRef which holds a reference to Application. It exposes a few utility methods to get view roots and activities.

ApplicationInspector has a few template methods for useful things which are not used in this diff and most likely will either be moved/deleted/changed on the final implementation.

Reviewed By: LukeDefeo

Differential Revision: D38829523

fbshipit-source-id: b8aeb133dceb3af42b5f7d6851ef531d35fc7d69
  • Loading branch information
lblasa authored and facebook-github-bot committed Aug 19, 2022
1 parent c861b3a commit dc28e2a
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.flipper.plugins.uidebugger.core

import android.view.View
import android.view.ViewTreeObserver
import com.facebook.flipper.plugins.uidebugger.commands.Context
import java.util.List

class ApplicationInspector(val context: Context) {

fun traverse(view: View) {
val inspector =
LayoutVisitor.create(
object : LayoutVisitor.Visitor {
override fun visit(view: View) {}
})
inspector.traverse(view)
}

fun attachListeners(view: View) {
// An OnGlobalLayoutListener watches the entire hierarchy for layout changes
// (so registering one of these on any View in a hierarchy will cause it to be triggered
// when any View in that hierarchy is laid out or changes visibility).
view
.getViewTreeObserver()
.addOnGlobalLayoutListener(
object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {}
})
view
.getViewTreeObserver()
.addOnPreDrawListener(
object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
return true
}
})
}

fun observe() {
val rootResolver = RootViewResolver()
rootResolver.attachListener(
object : RootViewResolver.Listener {
override fun onRootViewAdded(view: View) {
attachListeners(view)
}

override fun onRootViewRemoved(view: View) {}

override fun onRootViewsChanged(views: List<View>) {}
})

val activeRoots = rootResolver.listActiveRootViews()
activeRoots?.let { roots ->
for (root: RootViewResolver.RootView in roots) {
traverse(root.view)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.flipper.plugins.uidebugger.core

import android.app.Activity
import android.app.Application
import android.os.Bundle
import android.view.View
import java.lang.ref.WeakReference

class ApplicationRef(val application: Application) : Application.ActivityLifecycleCallbacks {
interface ActivityStackChangedListener {
fun onActivityStackChanged(stack: List<Activity>)
}

interface ActivityDestroyedListener {
fun onActivityDestroyed(activity: Activity)
}

private val rootsResolver: RootViewResolver
private val activities: MutableList<WeakReference<Activity>>
private var activityStackChangedlistener: ActivityStackChangedListener? = null
private var activityDestroyedListener: ActivityDestroyedListener? = null

override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
activities.add(WeakReference<Activity>(activity))
activityStackChangedlistener?.let { listener ->
listener.onActivityStackChanged(this.activitiesStack)
}
}
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) {
val activityIterator: MutableIterator<WeakReference<Activity>> = activities.iterator()

while (activityIterator.hasNext()) {
if (activityIterator.next().get() === activity) {
activityIterator.remove()
}
}

activityDestroyedListener?.let { listener -> listener.onActivityDestroyed(activity) }

activityStackChangedlistener?.let { listener ->
listener.onActivityStackChanged(this.activitiesStack)
}
}

fun setActivityStackChangedListener(listener: ActivityStackChangedListener?) {
activityStackChangedlistener = listener
}

fun setActivityDestroyedListener(listener: ActivityDestroyedListener?) {
activityDestroyedListener = listener
}

val activitiesStack: List<Activity>
get() {
val stack: MutableList<Activity> = ArrayList<Activity>(activities.size)
val activityIterator: MutableIterator<WeakReference<Activity>> = activities.iterator()
while (activityIterator.hasNext()) {
val activity: Activity? = activityIterator.next().get()
if (activity == null) {
activityIterator.remove()
} else {
stack.add(activity)
}
}
return stack
}

val rootViews: List<View>
get() {
val roots = rootsResolver.listActiveRootViews()
roots?.let { roots ->
val viewRoots: MutableList<View> = ArrayList<View>(roots.size)
for (root in roots) {
viewRoots.add(root.view)
}
return viewRoots
}

return emptyList()
}

init {
rootsResolver = RootViewResolver()
application.registerActivityLifecycleCallbacks(this)
activities = ArrayList<WeakReference<Activity>>()
}
}

0 comments on commit dc28e2a

Please sign in to comment.