1
1
package io.github.sceneview.node
2
2
3
3
import android.content.Context
4
+ import android.content.ContextWrapper
4
5
import android.graphics.Canvas
5
- import android.graphics.ImageFormat
6
- import android.graphics.Picture
7
6
import android.graphics.PixelFormat
8
7
import android.graphics.PorterDuff
9
- import android.media.ImageReader
10
- import android.os.Build
11
- import android.os.Handler
12
- import android.os.Looper
8
+ import android.graphics.SurfaceTexture
13
9
import android.util.AttributeSet
14
10
import android.view.LayoutInflater
15
11
import android.view.MotionEvent
16
12
import android.view.Surface
17
13
import android.view.View
18
14
import android.view.WindowManager.LayoutParams
19
15
import android.widget.FrameLayout
16
+ import androidx.activity.ComponentActivity
17
+ import androidx.activity.setViewTreeFullyDrawnReporterOwner
18
+ import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
20
19
import androidx.annotation.LayoutRes
21
- import androidx.annotation.RequiresApi
22
20
import androidx.compose.runtime.Composable
23
21
import androidx.compose.ui.platform.ComposeView
24
22
import androidx.compose.ui.platform.ViewCompositionStrategy
23
+ import androidx.lifecycle.setViewTreeLifecycleOwner
24
+ import androidx.lifecycle.setViewTreeViewModelStoreOwner
25
+ import androidx.savedstate.setViewTreeSavedStateRegistryOwner
25
26
import com.google.android.filament.Engine
26
27
import com.google.android.filament.MaterialInstance
27
28
import com.google.android.filament.RenderableManager
@@ -60,21 +61,15 @@ import io.github.sceneview.safeDestroyTexture
60
61
* (water, mirror surfaces, front camera in AR, etc.).
61
62
* True to invert front faces, false otherwise
62
63
*/
63
- @RequiresApi(Build .VERSION_CODES .P )
64
64
class ViewNode2 (
65
65
engine : Engine ,
66
66
val windowManager : WindowManager ,
67
67
materialLoader : MaterialLoader ,
68
68
view : View ,
69
69
unlit : Boolean = false ,
70
70
invertFrontFaceWinding : Boolean = false ,
71
- // This seems a little high, but lower values cause occasional "client tried to acquire
72
- // more than maxImages buffers" on a Pixel 3
73
- val imageReaderMaxImages : Int = 7
74
71
) : PlaneNode(engine = engine) {
75
72
76
- var surface: Surface ? = null
77
-
78
73
// Updated when the view is added to the view manager
79
74
var pxPerUnits = 250.0f
80
75
set(value) {
@@ -92,11 +87,11 @@ class ViewNode2(
92
87
addView(view)
93
88
}
94
89
95
- private var imageReader: ImageReader ? = null
96
- private val picture = Picture ()
97
- private val directImageHandler = Handler (Looper .getMainLooper())
90
+ private val surfaceTexture = SurfaceTexture (0 ).also { it.detachFromGLContext() }
91
+ private val surface = Surface (surfaceTexture)
98
92
99
93
val stream: Stream = Stream .Builder ()
94
+ .stream(surfaceTexture)
100
95
.build(engine)
101
96
102
97
val texture: Texture = Texture .Builder ()
@@ -295,13 +290,14 @@ class ViewNode2(
295
290
// }
296
291
297
292
override fun destroy () {
298
- super .destroy()
293
+
294
+ windowManager.removeView(layout)
299
295
300
296
engine.safeDestroyMaterialInstance(materialInstance)
301
297
engine.safeDestroyTexture(texture)
302
298
engine.safeDestroyStream(stream)
303
299
304
- windowManager.removeView(layout )
300
+ super .destroy( )
305
301
}
306
302
307
303
/* *
@@ -320,7 +316,6 @@ class ViewNode2(
320
316
* the view will not be marked as dirty when child views are animating when hardware
321
317
* accelerated.
322
318
*/
323
- @RequiresApi(Build .VERSION_CODES .P )
324
319
inner class Layout @JvmOverloads constructor(
325
320
context : Context ,
326
321
attrs : AttributeSet ? = null ,
@@ -332,15 +327,8 @@ class ViewNode2(
332
327
super .onLayout(changed, left, top, right, bottom)
333
328
334
329
// Only called when we first get View size
335
- imageReader?.close()
336
- imageReader = ImageReader .newInstance(
337
- width,
338
- height,
339
- ImageFormat .RGB_565 ,
340
- imageReaderMaxImages
341
- )
342
- surface?.release()
343
- surface = imageReader?.surface
330
+ surfaceTexture.setDefaultBufferSize(width, height)
331
+
344
332
}
345
333
346
334
override fun onSizeChanged (width : Int , height : Int , oldWidth : Int , oldHeight : Int ) {
@@ -351,30 +339,13 @@ class ViewNode2(
351
339
352
340
override fun dispatchDraw (canvas : Canvas ) {
353
341
if (! isAttachedToWindow) return
354
- // Check for Stream validity
355
- val stream = stream.takeIf { it.timestamp > 0 } ? : return
356
342
357
343
// Sanity that the surface is valid.
358
- val viewSurface = surface?.takeIf { it.isValid } ? : return
359
- if (isDirty) {
360
- val pictureCanvas = picture.beginRecording(width, height)
361
- pictureCanvas.drawColor(android.graphics.Color .TRANSPARENT , PorterDuff .Mode .CLEAR )
362
- super .dispatchDraw(pictureCanvas)
363
- picture.endRecording()
364
- val surfaceCanvas = viewSurface.lockCanvas(null )
365
- picture.draw(surfaceCanvas)
366
- viewSurface.unlockCanvasAndPost(surfaceCanvas)
367
-
368
- val image = imageReader!! .acquireLatestImage()
369
- stream.setAcquiredImage(
370
- image.hardwareBuffer!! ,
371
- directImageHandler
372
- ) {
373
- image.close()
374
- }
375
- }
376
- // Ask for redraw to update on each frames until stream is null
377
- invalidate()
344
+ val viewSurface = surface.takeIf { it.isValid } ? : return
345
+ val surfaceCanvas = viewSurface.lockCanvas(null )
346
+ surfaceCanvas.drawColor(android.graphics.Color .TRANSPARENT , PorterDuff .Mode .CLEAR )
347
+ super .dispatchDraw(surfaceCanvas)
348
+ viewSurface.unlockCanvasAndPost(surfaceCanvas)
378
349
}
379
350
}
380
351
@@ -383,7 +354,17 @@ class ViewNode2(
383
354
private val windowManager =
384
355
context.getSystemService(Context .WINDOW_SERVICE ) as android.view.WindowManager
385
356
386
- val layout by lazy { FrameLayout (context) }
357
+ val layout by lazy {
358
+ FrameLayout (context).also {
359
+ context.findActivity()?.let { activity ->
360
+ it.setViewTreeLifecycleOwner(activity)
361
+ it.setViewTreeSavedStateRegistryOwner(activity)
362
+ it.setViewTreeViewModelStoreOwner(activity)
363
+ it.setViewTreeFullyDrawnReporterOwner(activity)
364
+ it.setViewTreeOnBackPressedDispatcherOwner(activity)
365
+ }
366
+ }
367
+ }
387
368
388
369
fun addView (view : View ) = layout.addView(view)
389
370
fun addView (view : View , params : FrameLayout .LayoutParams ) = layout.addView(view, params)
@@ -442,3 +423,8 @@ class ViewNode2(
442
423
}
443
424
}
444
425
}
426
+
427
+
428
+ private fun Context.findActivity (): ComponentActivity ? {
429
+ return generateSequence(this ) { (it as ? ContextWrapper )?.baseContext }.filterIsInstance<ComponentActivity >().firstOrNull()
430
+ }
0 commit comments