[Java for Android App Development] krzema12:
First of all, this is my first post here so hello everyone.

I'm writing an app that requires displaying a semi-transparent PNG layer over a camera preview. Everything was fine until I wanted to publish it and make sure it works also on Android 2.x. It seems that on older versions of Android, the camera preview causes the drawable (in my case, a subclass of ImageView) to not show. The whole screen is white, but the buttons are visible. When I get rid of the preview, it works just fine - the drawable is visible as it should. It works like this both on the emulator and on real devices.

Here is my code (the whole project is in the attachment). The most interesting and probably guilty class is CameraPreview. The code doesn't crash, there's also no exceptions or other behavior like this.

MainActivity.java

public class MainActivity extends Activity
{
CameraPreview mPreview;

[MENTION=439709]override[/MENTION]
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

setContentView(R.layout.activity_main);

mPreview = (CameraPreview)this.findViewById(R.id.cameraPreview);
}

[MENTION=439709]override[/MENTION]
protected void onResume()
{
super.onResume();
mPreview.resume();
}

[MENTION=439709]override[/MENTION]
protected void onPause()
{
super.onPause();
mPreview.pause();
}
}

CameraPreview.java

class CameraPreview extends ViewGroup implements SurfaceHolder.Callback
{
private final String TAG = "Preview";

SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Context mContext;
int currentCamera = 0;
int noOfCameras = 0;

public CameraPreview(Context context)
{
super(context);
}

[MENTION=1299008]supp[/MENTION]ressLint("NewApi")
[MENTION=1299008]supp[/MENTION]ressWarnings("deprecation")
public CameraPreview(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
mContext = context;

mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);

mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);

if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

// checking what cameras we have

if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO)
{
noOfCameras = Camera.getNumberOfCameras();

CameraInfo cameraInfo = new CameraInfo();

for(int i=0; i<noOfCameras; i++)
{
Camera.getCameraInfo(i, cameraInfo);

if(cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
{
currentCamera = i;
break;
}
}
}
}

public CameraPreview(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}

public void setCamera(Camera camera)
{
if(mCamera != null && camera == null)
mCamera.release();

mCamera = camera;

if(mCamera != null)
{
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}

[MENTION=439709]override[/MENTION]
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);

if(mSupportedPreviewSizes != null)
mPreviewSize = getOptimalPreviewSize(width, height);
}

[MENTION=439709]override[/MENTION]
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
if(changed && getChildCount() > 0)
{
final View child = mSurfaceView;

final int width = r - l;
final int height = b - t;

int previewWidth = width;
int previewHeight = height;

if(mPreviewSize != null)
{
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}

final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight)/2, width, (height + scaledChildHeight) / 2);
}
}

public void surfaceCreated(SurfaceHolder holder)
{
try
{
if(mCamera != null)
mCamera.setPreviewDisplay(holder);
}
catch(IOException exception)
{
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}

public void surfaceDestroyed(SurfaceHolder holder)
{
if(mCamera != null)
mCamera.stopPreview();
}

// Chooses such preview's size that it just one "step" wider
// than needed. This ensures sharpness of the preview.
private Size getOptimalPreviewSize(int w, int h)
{
Size optimalSize = null;
int optimalWidth = 0;

for(Size size : mSupportedPreviewSizes)
{
if(size.width > optimalWidth)
{
optimalSize = size;

if(size.width >= w)
break;
}
}

return optimalSize;
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
{
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();

mCamera.setParameters(parameters);
mCamera.startPreview();
}

public void resume()
{
setCamera(Camera.open());
}

public void pause()
{
setCamera(null);
}
}

CustomImageView.java

// aligns the content image to the top
public class CustomImageView extends ImageView
{
public CustomImageView(Context context, AttributeSet attrs)
{
super(context, attrs);

setScaleType(ScaleType.MATRIX);
}

[MENTION=439709]override[/MENTION]
protected boolean setFrame(int l, int t, int r, int b)
{
Matrix matrix = getImageMatrix();
float scaleFactor = getWidth()/(float)getDrawable().getIntrinsicWidth();
matrix.setScale(scaleFactor, scaleFactor, 0, 0);
setImageMatrix(matrix);

return super.setFrame(l, t, r, b);
}
}

activity_main.xml

<FrameLayout xmlns:android="h t t p:// schemas.android.com /apk/res/android"
xmlns:tools="h t t p:/ /schemas.android.com /tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity"
android:background="#ffe9eaed" >

<com.example.drawabletest.CameraPreview
android:id="@+id/cameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00FFFF" />

<com.example.drawabletest.CustomImageView
android:id="@+id/fbTemplate"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:src="@drawable/template2" />

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Small Text"
android:textAppearance="?android:attr/textAppearanceSmall" />

</FrameLayout>

Also, I'm not sure why the preview itself doesn't work. I've read that on Android 2.x emulators, the test image from the emulated camera is just this plain white by design, so I assumed it's ok. However, my friend tested the app on his phone with Android 2.3 and the preview appeared to be plain black. I guess it's a subject for a separate question, but maybe you'll notice something in the code.

I've spent a few days now to solve these two problems, so any clues would be really helpful. Thank you!