Skip to content

Commit

Permalink
Fixed AR Lifecycle observer
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasGorisse committed Oct 27, 2023
1 parent d2bfbfc commit 64b706a
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 62 deletions.
3 changes: 2 additions & 1 deletion arsceneview/src/main/java/io/github/sceneview/ar/ARCore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ class ARCore(
var checkCameraPermission = true

/**
* ### Enable/Disable Google Play Services for AR availability check, auto install and update
* Enable/Disable Google Play Services for AR availability check, auto install and update
*/
var checkAvailability = true

lateinit var features: Set<Session.Feature>
lateinit var cameraPermissionLauncher: ActivityResultLauncher<String>
private var cameraPermissionRequested = false
lateinit var appSettingsLauncher: ActivityResultLauncher<Intent>

private var appSettingsRequested = false
private var installRequested = false
internal var session: ARSession? = null
Expand Down
49 changes: 32 additions & 17 deletions arsceneview/src/main/java/io/github/sceneview/ar/ARSceneView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.util.AttributeSet
import android.util.Size
import android.view.MotionEvent
import androidx.activity.ComponentActivity
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.google.android.filament.Engine
Expand Down Expand Up @@ -318,8 +319,6 @@ open class ARSceneView @JvmOverloads constructor(
hitResult: HitResult
) -> Unit)? = null

private var _onSessionCreated = mutableListOf<(session: Session) -> Unit>()

val onLightEstimationUpdated: ((estimation: LightEstimator.Estimation?) -> Unit)? = null

var onTrackingFailureChanged: ((trackingFailureReason: TrackingFailureReason?) -> Unit)? =
Expand All @@ -328,25 +327,22 @@ open class ARSceneView @JvmOverloads constructor(
override val cameraGestureDetector = null
override val cameraManipulator = null

private val lifecycleObserver = LifeCycleObserver()
override var lifecycle: Lifecycle?
get() = super.lifecycle
set(value) {
super.lifecycle?.removeObserver(lifecycleObserver)
super.lifecycle = value
value?.addObserver(lifecycleObserver)
}

private var _onSessionCreated = mutableListOf<(session: Session) -> Unit>()

init {
setCameraNode(sharedCameraNode ?: createCameraNode(engine).also {
defaultCameraNode = it
})
}

override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
arCore.create(context, activity, sessionFeatures)
}

override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
arCore.resume(context, activity)
}

override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
arCore.pause()
sharedLifecycle?.addObserver(lifecycleObserver)
}

override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
Expand Down Expand Up @@ -558,6 +554,25 @@ open class ARSceneView @JvmOverloads constructor(
}
}


private inner class LifeCycleObserver : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
arCore.create(context, activity, sessionFeatures)
}

override fun onResume(owner: LifecycleOwner) {
arCore.resume(context, activity)
}

override fun onPause(owner: LifecycleOwner) {
arCore.pause()
}

override fun onDestroy(owner: LifecycleOwner) {
arCore.destroy()
}
}

companion object {
fun createEglContext() = SceneView.createEglContext()
fun createEngine(eglContext: EGLContext) = SceneView.createEngine(eglContext)
Expand Down
84 changes: 40 additions & 44 deletions sceneview/src/main/java/io/github/sceneview/SceneView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import android.media.MediaRecorder
import android.opengl.EGLContext
import android.util.AttributeSet
import android.view.*
import android.view.Choreographer.FrameCallback
import androidx.activity.ComponentActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.findFragment
Expand Down Expand Up @@ -144,7 +143,6 @@ open class SceneView @JvmOverloads constructor(
*/
sharedSkybox: Skybox? = null
) : SurfaceView(context, attrs, defStyleAttr, defStyleRes),
DefaultLifecycleObserver,
GestureDetector.OnGestureListener by GestureDetector.SimpleOnGestureListener() {

private var defaultEngine: Engine? = null
Expand Down Expand Up @@ -346,13 +344,6 @@ open class SceneView @JvmOverloads constructor(
context as? ComponentActivity
}

var lifecycle: Lifecycle? = sharedLifecycle
set(value) {
field?.removeObserver(this)
field = value
value?.addObserver(this)
}

protected open val cameraGestureDetector: CameraGestureDetector? by lazy {
CameraGestureDetector(this, CameraGestureListener())
}
Expand All @@ -379,14 +370,15 @@ open class SceneView @JvmOverloads constructor(
private val displayHelper = DisplayHelper(context)
private var swapChain: SwapChain? = null

private val frameCallback = object : FrameCallback {
override fun doFrame(timestamp: Long) {
// Always post the callback for the next frame.
Choreographer.getInstance().postFrameCallback(this)

onFrame(timestamp)
private val lifecycleObserver = LifeCycleObserver()
open var lifecycle: Lifecycle? = sharedLifecycle
set(value) {
field?.removeObserver(lifecycleObserver)
field = value
value?.addObserver(lifecycleObserver)
}
}

private val frameCallback = FrameCallback()

private var _viewAttachmentManager: ViewAttachmentManager? = null
protected val viewAttachmentManager
Expand All @@ -413,7 +405,7 @@ open class SceneView @JvmOverloads constructor(
defaultCameraNode = it
})

lifecycle?.addObserver(this)
sharedLifecycle?.addObserver(lifecycleObserver)
}

/**
Expand Down Expand Up @@ -579,25 +571,6 @@ open class SceneView @JvmOverloads constructor(
lastFrameTimeNanos = frameTimeNanos
}

override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)

_viewAttachmentManager?.onResume()

// Start the drawing when the renderer is resumed. Remove and re-add the callback
// to avoid getting called twice.
Choreographer.getInstance().removeFrameCallback(frameCallback)
Choreographer.getInstance().postFrameCallback(frameCallback)
}

override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)

Choreographer.getInstance().removeFrameCallback(frameCallback)

_viewAttachmentManager?.onPause()
}

override fun onAttachedToWindow() {
super.onAttachedToWindow()

Expand All @@ -619,13 +592,6 @@ open class SceneView @JvmOverloads constructor(
cameraNode.updateProjection()
}

override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
if (!isDestroyed) {
destroy()
}
}

/**
* Invoked when the `SceneView` is tapped.
*
Expand Down Expand Up @@ -689,7 +655,37 @@ open class SceneView @JvmOverloads constructor(
}
}

inner class SurfaceCallback : UiHelper.RendererCallback {
private inner class LifeCycleObserver : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
_viewAttachmentManager?.onResume()

// Start the drawing when the renderer is resumed. Remove and re-add the callback
// to avoid getting called twice.
Choreographer.getInstance().removeFrameCallback(frameCallback)
Choreographer.getInstance().postFrameCallback(frameCallback)
}

override fun onPause(owner: LifecycleOwner) {
Choreographer.getInstance().removeFrameCallback(frameCallback)

_viewAttachmentManager?.onPause()
}

override fun onDestroy(owner: LifecycleOwner) {
destroy()
}
}

private inner class FrameCallback : Choreographer.FrameCallback {
override fun doFrame(timestamp: Long) {
// Always post the callback for the next frame.
Choreographer.getInstance().postFrameCallback(this)

onFrame(timestamp)
}
}

private inner class SurfaceCallback : UiHelper.RendererCallback {
override fun onNativeWindowChanged(surface: Surface) {
swapChain?.let { runCatching { engine.destroySwapChain(it) } }
swapChain = engine.createSwapChain(surface)
Expand Down

0 comments on commit 64b706a

Please sign in to comment.