Android : Surfaceholder.addCallback Not Working; surfaceCreated, surfaceChanged, and surfaceDestroyed Never Being Called

on Friday, July 11, 2014


I am implementing a camera preview using Scala based on the code in com.example.android.apis.graphics.CameraPreview in Android ApiDemos. However, the methods of SurfaceHolder.Callback (surfaceCreated, surfaceChanged, and surfaceDestroyed) seem never being called. Here is the code:



class TakePictureActivity extends ActivityWithLog {
lazy val preview = findViewById(R.id.preview).asInstanceOf[CameraPreview]

override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
setContentView(R.layout.take_picture)
}

override def onResume {
super.onResume()
preview.camera = Camera.open()
}

override def onPause {
super.onPause()
for (c <- Option(preview.camera)) {
c.release()
preview.camera = null
}
}
}

class CameraPreview(context: Context,
attrs: AttributeSet,
defStyle: Int)
extends ViewGroup(context, attrs, defStyle)
with SurfaceHolder.Callback
with LogTag {
def this(context: Context, attrs: AttributeSet) = this(context, attrs, 0)
def this(context: Context) = this(context, null)

private var maybeCamera: Option[Camera] = None

def camera = maybeCamera.getOrElse(null)

def camera_=(c: Camera) {
maybeCamera = Option(c)
if (maybeCamera.nonEmpty) requestLayout()
}

private var previewSize: Option[Camera#Size] = None

def optimalPreviewSize(sizes: Seq[Camera#Size],
targetWidth: Int, targetHeight: Int) = {
val targetRatio = targetWidth.asInstanceOf[Double] / targetHeight
val targetArea = targetWidth * targetHeight
def closestInArea(sizes: Seq[Camera#Size]) =
sizes.minBy(s => abs(s.width * s.height - targetArea))
sizes.filter { size =>
val r = size.width.asInstanceOf[Double] / size.height
abs(r - targetRatio) < 0.1
} match {
case Seq() => closestInArea(sizes)
case xs => closestInArea(xs)
}
}

override def onMeasure(widthMeasureSpec: Int,
heightMeasureSpec: Int) {
val w = View.resolveSize(getSuggestedMinimumWidth, widthMeasureSpec)
val h = View.resolveSize(getSuggestedMinimumHeight, heightMeasureSpec)
setMeasuredDimension(w, h)
for (c <- maybeCamera) {
val sizes = c.getParameters.getSupportedPreviewSizes.asScala
previewSize = Some(optimalPreviewSize(sizes, w, h))
}
}

override def onLayout(changed: Boolean,
l: Int, t: Int, r: Int, b: Int) {
if (changed && getChildCount > 0) {
val child = getChildAt(0)
val (w, h) = (r - l, b - t)
val (pw, ph) = previewSize match {
case Some(s) => (s.width, s.height)
case None => (w, h)
}
if (w * ph > h * pw) {
val scaledChildWidth = pw * h / ph
child.layout((w - scaledChildWidth) / 2, 0,
(w + scaledChildWidth) / 2, h)
} else {
val scaledChildHeight = ph * w / pw
child.layout(0, (h - scaledChildHeight) / 2,
w, (h - scaledChildHeight) / 2)
}
}
}

val surfaceView = new SurfaceView(context)
addView(surfaceView)
surfaceView.getHolder.addCallback(this)

def surfaceCreated(holder: SurfaceHolder) {
Log.d(TAG, "surfaceCreated")
for (c <- maybeCamera) c.setPreviewDisplay(holder)
}

def surfaceChanged(holder: SurfaceHolder,
format: Int, width: Int, height: Int) {
Log.d(TAG, "surfaceChanged")
for (camera <- maybeCamera;
preSize <- previewSize) {
val params = camera.getParameters
params.setPreviewSize(preSize.width, preSize.height)
Log.d(TAG, s"setPreviewSize: ${preSize.width}x${preSize.height}")
requestLayout()
camera.setParameters(params)
camera.startPreview()
}
}

def surfaceDestroyed(holder: SurfaceHolder) {
Log.d(TAG, "surfaceDestroyed")
for (c <- maybeCamera) c.stopPreview()
}
}


and layout:



<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CameraPreview android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>


Can anyone help me solve this problem? Thanks!


0 comments:

Post a Comment