In my Android app there is an Activity showing a Camera preview, implemented as a SurfaceView using the documentation here: http://developer.android.com/guide/topics/media/camera.html#custom-camera.
I want to show an ImageView on top of this SurfaceView from the start, but I also want to update its layout (width, height and source image) when the user takes a first photo.
My problem is that the code works in the first step, the image is shown over the SurfaceView when the Activity starts, but its layout doesn't change when I want to.
Here is the XML:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout_capture"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CaptureActivity" >
<RelativeLayout
android:id="#+id/camera_preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
>
<!-- Here I will programmatically add the SurfaceView -->
<ImageView
android:id="#+id/image_picture"
android:layout_width="100dp"
android:layout_height="80dp"
android:layout_centerInParent="true"
android:contentDescription="picture preview"
android:src="#drawable/image1" />
</RelativeLayout>
<Button
android:id="#+id/button_capture"
android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
/>
</FrameLayout>
The SurfaceView is added with this snippet:
mPreview = new CameraPreview(this, mCamera);
RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview, 0); //
This is the code that should update the ImageView (it's inside the onPictureTaken() method)... but it doesn't work:
LayoutInflater linf = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
FrameLayout frame = (FrameLayout) linf.inflate(R.layout.activity_capture, null);
ImageView imgw = (ImageView) frame.findViewById(R.id.image_left_picture); // get the ImageView
imgw.setImageResource(R.drawable.image2); // change its source image
imgw.setLayoutParams(new RelativeLayout.LayoutParams(w, h)); //change its size
invalidate(); // also tried to add this method call... nothing changes.
I think the problem is:
FrameLayout frame = (FrameLayout) linf.inflate(R.layout.activity_capture, null);
Have you added this layout to your view group? I didn't see your code. you just inflated it and set the image view inside of this layout.
Try this... it might be helpful to you...
public class CameraActivity extends Activity implements PictureCallback{
protected static final String EXTRA_IMAGE_PATH = "com.blundell.tut.cameraoverlay.ui.CameraActivity.EXTRA_IMAGE_PATH";
ImageView img;
private Camera camera;
private CameraPreview cameraPreview;
int windowwidth;
int windowheight;
#SuppressWarnings("unused")
private LayoutParams layoutParams;
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
windowwidth = getWindowManager().getDefaultDisplay().getWidth();
windowheight = getWindowManager().getDefaultDisplay().getHeight();
img=(ImageView) findViewById(R.id.img);
img.setImageResource(R.drawable.img1);
setResult(RESULT_CANCELED);
// Camera may be in use by another activity or the system or not available at all
camera = getCameraInstance();
if(cameraAvailable(camera)){
initCameraPreview();
} else {
finish();
}
}
// Show the camera view on the activity
private void initCameraPreview() {
cameraPreview = (CameraPreview) findViewById(R.id.camera_preview);
cameraPreview.init(camera);
cameraPreview.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
LayoutParams layoutParams = (LayoutParams) img
.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
if (x_cord > windowwidth) {
x_cord = windowwidth;
}
if (y_cord > windowheight) {
y_cord = windowheight;
}
layoutParams.leftMargin = x_cord - 25;
layoutParams.topMargin = y_cord - 75;
img.setLayoutParams(layoutParams);
break;
default:
break;
}
return true;
}
});
}
#FromXML
public void onCaptureClick(View button){
// Take a picture with a callback when the photo has been created
// Here you can add callbacks if you want to give feedback when the picture is being taken
camera.takePicture(null, null, this);
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d("Picture taken");
String path = savePictureToFileSystem(data);
setResult(path);
finish();
}
private static String savePictureToFileSystem(byte[] data) {
File file = getOutputMediaFile();
saveToFile(data, file);
return file.getAbsolutePath();
}
private void setResult(String path) {
Intent intent = new Intent();
intent.putExtra(EXTRA_IMAGE_PATH, path);
setResult(RESULT_OK, intent);
}
// ALWAYS remember to release the camera when you are finished
#Override
protected void onPause() {
super.onPause();
releaseCamera();
}
private void releaseCamera() {
if(camera != null){
camera.release();
camera = null;
}
}
}
And Camera Preiew...
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private Camera camera;
private SurfaceHolder holder;
public CameraPreview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CameraPreview(Context context) {
super(context);
}
public void init(Camera camera) {
this.camera = camera;
initSurfaceHolder();
}
#SuppressWarnings("deprecation") // needed for < 3.0
private void initSurfaceHolder() {
holder = getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
initCamera(holder);
}
private void initCamera(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (Exception e) {
Log.d("Error setting camera preview", e);
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
Related
I have an activity which creates my custom SurfaceView for camera previewing in center of FrameLayout. In xml I have a FrameLayout with button and ImageView. When I click on button, I want ImageView shows over SurfaceView in center of FrameLayout. So when I run application I catch warning:
Skipped XX frames! The application may be doing too much work on its main thread
Here is my XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.rcd.perfecto.ui.CameraActivity">
<FrameLayout
android:id="#+id/fl_camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/iv_avatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ic_launcher"/>
<Button
android:id="#+id/btn_photo_capture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/btn_photo_capture"
android:layout_gravity="center_horizontal|bottom"/>
</FrameLayout>
</LinearLayout>
Here is my custom SurfaceView
public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
private Path mClipPath;
private Camera mCamera;
private WeakReference<FrameLayout> mFrameLayoutWeakReference;
private Context mContext;
private SurfaceHolder mHolder;
public CameraView(Context context) {
super(context);
init(context);
}
public CameraView(Context context, Camera camera, FrameLayout layout) {
super(context);
mCamera = camera;
mFrameLayoutWeakReference = new WeakReference<FrameLayout>(layout);
mHolder = getHolder();
mHolder.addCallback(this);
init(context);
}
public CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CameraView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
mContext = context;
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
float radius;
FrameLayout layout = mFrameLayoutWeakReference.get();
if (display.getRotation() == Surface.ROTATION_0 || display.getRotation() == Surface.ROTATION_180) {
radius = layout.getWidth() / 2;
} else {
radius = layout.getHeight() / 2;
}
mClipPath = new Path();
mClipPath.addCircle(layout.getWidth() / 2, layout.getHeight() / 2, radius, Path.Direction.CW);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.clipPath(mClipPath);
super.dispatchDraw(canvas);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
}
Camera.Parameters parameters = mCamera.getParameters();
Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
parameters.setPreviewSize(height, width);
mCamera.setDisplayOrientation(90);
}
if (display.getRotation() == Surface.ROTATION_90) {
parameters.setPreviewSize(width, height);
}
if (display.getRotation() == Surface.ROTATION_180) {
parameters.setPreviewSize(height, width);
}
if (display.getRotation() == Surface.ROTATION_270) {
parameters.setPreviewSize(width, height);
mCamera.setDisplayOrientation(180);
}
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
And my activity:
public class CameraActivity extends AppCompatActivity {
#Bind(R.id.btn_photo_capture) Button mPhotoCaptureButton;
#Bind(R.id.fl_camera_preview) FrameLayout mCameraPreviewFrameLayout;
#Bind(R.id.iv_avatar) CircleImageView mAvatarImageView;
private Camera mCamera;
private CameraView mCameraView;
public CameraActivity() {
}
#OnClick(R.id.btn_photo_capture)
void takePicture() {
if (mAvatarImageView.getVisibility() == View.VISIBLE) {
mAvatarImageView.setVisibility(View.GONE);
} else {
mAvatarImageView.setVisibility(View.VISIBLE);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
ButterKnife.bind(this);
if (checkCameraHardware()) {
if (Camera.getNumberOfCameras() > 1) {
mCamera = getCameraInstance(Camera.CameraInfo.CAMERA_FACING_FRONT);
} else mCamera = getCameraInstance();
}
ViewTreeObserver observer = mCameraPreviewFrameLayout.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mCameraView = new CameraView(CameraActivity.this, mCamera, mCameraPreviewFrameLayout);
mCameraPreviewFrameLayout.addView(mCameraView, 0);
}
});
}
private static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
e.printStackTrace();
}
return c;
}
private static Camera getCameraInstance(int id) {
Camera c = null;
try {
c = Camera.open(id);
} catch (Exception e) {
e.printStackTrace();
}
return c;
}
private boolean checkCameraHardware() {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
}
So my question is how can I avoid warning above or is there another way to set surfaceview in center of FrameLayout programmatically?
I am trying to place an imageview over a Camera surfaceview, when the application starts the imageview is on top of the camera preview but after a picture is taken and is set to the imageview the RelativeLayout that the camera preview is nested in moves forward when startpreview is called to start the camera again so the camera preview ends up above the imageview. There are buttons in the same layout placed after the imageview in the xml layout and those are not affected. If I don't start the camera again after a picture the imageview has it's image and is visible. Dumping the view hierarchy verifies the same. As far as I can tell this should be something fairly straight-forward, so I'm not sure where I'm going wrong.
UPDATE: I have also attempted to add a completely new ImageView with the bitmap programmatically after the camera is started and that ImageView is moved behind as well.
XML:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:id="#+id/add_activity"
android:layout_height="fill_parent"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/camera_preview"
/>
<ImageView
android:layout_width="fill_parent"
android:id="#+id/beforeImageView"
android:src="#drawable/app_icon"
android:alpha="0.2"
android:layout_height="fill_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back"
android:id="#+id/close_camera"
android:layout_gravity="bottom|left"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:gravity="bottom|left"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" />
<Button
android:id="#+id/button_capture"
android:text="Before"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="20dp"
android:background="#color/purple"
android:textColor="#color/white"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/add_progress_bar"
android:layout_gravity="center" />
</FrameLayout>
JAVA:
public class AddActivity extends Activity {
private Camera mCamera;
CameraPreview mPreview;
private RelativeLayout preview;
boolean useFrontCamera = true;
boolean tookBeforeImage = false;
boolean tookAfterImage = false;
Bitmap beforeImage;
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
//Hide Notification and Action Bars
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
ActionBar actionBar = getActionBar();
actionBar.hide();
progressBar = (ProgressBar) findViewById(R.id.add_progress_bar);
progressBar.setVisibility(View.INVISIBLE);
boolean cameraCheck = checkCameraHardware(getApplicationContext());
if (cameraCheck) {
StartCamera cameraLaunch = new StartCamera();
cameraLaunch.execute();
}
Button closeCameraButton = (Button) findViewById(R.id.close_camera);
closeCameraButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
releaseCamera();
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
decorView.setSystemUiVisibility(uiOptions);
ActionBar actionBar = getActionBar();
actionBar.show();
finish();
}
});
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCamera.takePicture(null,null,mPicture);
}
});
}
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true;
} else {
return false;
}
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
#Override
protected void onPause() {
super.onPause();
releaseCamera();
}
#Override
public void onBackPressed() {
releaseCamera();
super.onBackPressed();
}
#Override
protected void onResume() {
super.onResume();
//Hide Notification and Action Bars
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
ActionBar actionBar = getActionBar();
actionBar.hide();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
//getMenuInflater().inflate(R.menu.menu_add, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
//return true;
}
return super.onOptionsItemSelected(item);
}
private class StartCamera extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected String doInBackground(String... params) {
try {
if (useFrontCamera) {
mCamera = Camera.open();
mCamera.enableShutterSound(true);
} else {
//Flip Camera
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
mPreview = new CameraPreview(getApplicationContext(),mCamera);
preview = (RelativeLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview,0);
progressBar.setVisibility(View.INVISIBLE);
}
}
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Display display = getWindowManager().getDefaultDisplay();
int rotation = 0;
switch (display.getRotation()) {
case Surface.ROTATION_0: // This is display orientation
rotation = 90;
break;
case Surface.ROTATION_90:
rotation = 0;
break;
case Surface.ROTATION_180:
rotation = 270;
break;
case Surface.ROTATION_270:
rotation = 180;
break;
}
Bitmap bitmap = ImageTools.toBitmap(data);
bitmap = ImageTools.rotate(bitmap, rotation);
if (!tookBeforeImage) {
beforeImage = bitmap;
ResetCamera cameraReset = new ResetCamera();
cameraReset.execute();
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setText("After");
tookBeforeImage = true;
} else if (tookBeforeImage == true && tookAfterImage == false) {
} else {
}
}
};
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
this.setBackgroundColor(Color.TRANSPARENT);
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("Camera Error", "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d("Camera Error", "Error starting camera preview: " + e.getMessage());
}
}
}
private static class ImageTools {
public static Bitmap toBitmap(byte[] data) {
return BitmapFactory.decodeByteArray(data, 0, data.length);
}
public static Bitmap rotate(Bitmap in, int angle) {
Matrix mat = new Matrix();
mat.postRotate(angle);
return Bitmap.createBitmap(in, 0, 0, in.getWidth(), in.getHeight(), mat, true);
}
}
private class ResetCamera extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected String doInBackground(String... params) {
mCamera.startPreview();
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
ImageView beforeImageView = (ImageView) findViewById(R.id.beforeImageView);
beforeImageView.setImageBitmap(beforeImage);
beforeImageView.setImageAlpha(100);
//Trying to add programmatically still ends up behind Camera Preview
ImageView newBefore = (ImageView) new ImageView(getApplicationContext());
newBefore.setImageBitmap(beforeImage);
newBefore.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
preview.addView(newBefore,0);
progressBar.setVisibility(View.INVISIBLE);
}
}
}
It was due to trying to load too large of a bitmap, it was quietly throwing a notice in the log as it was unable to create a texture. Reducing the bitmap's size solved the issue.
I am new to Android and I am trying to add start and reset buttons with a custom surface view. I am able to draw canvas with a circle which is moving with touch.
Now my problem is that when I click the start button, the circle must take its initial position (10,10).
My activity class
public class OpenGlActivity extends Activity implements OnClickListener {
GameView GameView;
FrameLayout Frame;
LinearLayout canvas;
Button btnStart, btnReset;
TutorialThread GameThread;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set full screen view
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
GameView = new GameView(this);
btnStart = (Button) findViewById(R.id.btnStart);
btnStart.setOnClickListener(this);
btnReset = (Button) findViewById(R.id.btnReset);
btnReset.setOnClickListener(this);
GameView.setOnTouchListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
Log.i("openGl", "play called");
GameView.setState();
// drawView.invalidate();
break;
case R.id.btnReset:
// GameView.play=true;
// GameView.reset();
Log.i("openGl", "RESETcalled");
// drawView.invalidate();
break;
}
}
}
Custom surfaceview class and thread class
class GameView extends SurfaceView implements SurfaceHolder.Callback {
String TAG = "GameView";
private TutorialThread _thread;
Paint paint = new Paint();
Paint red = new Paint();
Paint black = new Paint();
int x = 20;
int y = 20;
public GameView(Context context) {
super(context);
// TODO Auto-generated constructor stub
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
// TODO Auto-generated constructor stub
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
red.setColor(Color.RED);
red.setAntiAlias(true);
black.setColor(Color.BLACK);
black.setAntiAlias(true);
setFocusable(true);
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
// TODO Auto-generated constructor stub
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
red.setColor(Color.RED);
red.setAntiAlias(true);
black.setColor(Color.BLACK);
black.setAntiAlias(true);
setFocusable(true);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
x = (int) event.getX();
y = (int) event.getY();
return true;
}
public void setState() {
Log.i(TAG, "in setState");
_thread.play();
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawCircle(x, y, 10, red);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
_thread.setRunning(true);
_thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}
class TutorialThread extends Thread {
String TAG = "TutorialThread";
private SurfaceHolder _surfaceHolder;
private GameView _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, GameView panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
public void play() {
synchronized (_surfaceHolder) {
_panel.x = 10;
_panel.y = 10;
Log.i(TAG, "in Play");
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.example.opengl.GameView
android:id="#+id/gameView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="#+id/btnReset"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Reset" />
</LinearLayout>
</FrameLayout>
I have not found any way to crop camera ppreview and then display it on the SurfaceView.
Android - Is it possible to crop camera preview?
You can do this without overlay views (which won't work in all situations).
Subclass ViewGroup, add the SurfaceView as the only child, then:
in onMeasure supply the cropped dimensions you want.
in onLayout, layout the SurfaceView with the un-cropped dimensions.
basically,
public class CroppedCameraPreview extends ViewGroup {
private SurfaceView cameraPreview;
public CroppedCameraPreview( Context context ) {
super( context );
// i'd probably create and add the SurfaceView here, but it doesn't matter
}
#Override
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) {
setMeasuredDimension( croppedWidth, croppedHeight );
}
#Override
protected void onLayout( boolean changed, int l, int t, int r, int b ) {
if ( cameraPreview != null ) {
cameraPreview.layout( 0, 0, actualPreviewWidth, actualPreviewHeight );
}
}
}
You could put the camera preview (SurfaceView) inside a LinearLayout that is inside a ScrollView. When the camera output is bigger than the LinearLayout you set you can programmatically scroll it and disable user scroll. This way you can emulate camera cropping in an easy way:
<ScrollView
android:id="#+id/scrollView"
android:layout_width="640dip"
android:layout_height="282dip"
android:scrollbars="none"
android:fillViewport="true">
<LinearLayout
android:id="#+id/linearLayoutBeautyContent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/surfaceViewBeautyCamera"/>
</LinearLayout>
</ScrollView>
Not directly. Camera API does now allow for offsets, and will squeeze image into surface
holder. But you can work around by placing overlays (other views) over it.
The code to programmatically scroll the image would be something like this:
public void setCameraOrientationOnOpen()
{
mCamera.stopPreview();
int rotation = getRotation();
Camera.Parameters currentCameraParameters = mCamera.getParameters();
List<Camera.Size> previewSizes = currentCameraParameters.getSupportedPreviewSizes();
mOptimalCameraSize = getOptimaPreviewCameraSize(previewSizes, (double)9/16);
currentCameraParameters.setPreviewSize(mOptimalCameraSize.width, mOptimalCameraSize.height);
mCamera.setParameters(currentCameraParameters);
float ratio = 100;
int ratio1 = (mSurfaceView.getLayoutParams().height * 100) / mOptimalCameraSize.width; //height
int ratio2 = (mSurfaceView.getLayoutParams().width * 100) / mOptimalCameraSize.height; //width
ratio = Math.max(ratio1, ratio2);
mSurfaceView.getLayoutParams().height = (int) ((mOptimalCameraSize.width * ratio) / 100);
mSurfaceView.getLayoutParams().width = (int) ((mOptimalCameraSize.height * ratio) / 100);
if(ratio > 100)
{
int offset = (mSurfaceView.getLayoutParams().height - mBoxHeight)/2;
mScrollView.scrollTo(0, offset); //center the image
}
mCamera.setDisplayOrientation(rotation);
mOptimalCameraSize = mCamera.getParameters().getPreviewSize();
}
I calculate the best preview size from the camera for my camera content box (ratio 16:9), then apply the calculated ratio to the image in order to keep the same ratio and finally calculate the needed scroll (the image would be on the middle)
Create a centered Frame Layout that will store the Camera Preview and overlay it with Views to "crop" it. When you create your view, dynamically stretch a transparent view that is centered as well.
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000" >
<FrameLayout
android:id="#+id/camera_preview_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerVertical="true" />
<View
android:id="#+id/transparent_window"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:layout_centerVertical="true"
android:background="#android:color/transparent" />
<View
android:id="#+id/black_top_box"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#id/transparent_window"
android:background="#000"/>
<View
android:id="#+id/black_bottom_box"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#id/transparent_window"
android:background="#000"/>
</RelativeLayout>
Then in the OnCreate() method of your activity class you can stretch the transparent view like this.
CameraActivity.java
final View transView = findViewById(R.id.transparent_window);
transView.post(new Runnable() {
#Override
public void run() {
RelativeLayout.LayoutParams params;
params = (RelativeLayout.LayoutParams) transView.getLayoutParams();
params.height = transView.getWidth();
transView.setLayoutParams(params);
transView.postInvalidate();
}
});
This is a screenshot from my phone of this. The gray blob in the middle is the camera's view of the floor through the transparent View
Here is a solution for orientation = landscape to complete #drees' excellent answer.
Just add layout-land folder in res folder, duplicate your entire layout xml and change the layout part of #drees' code to be like this:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/background_dark" >
<FrameLayout
android:id="#+id/frameSurface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#android:color/background_light"/>
<View
android:id="#+id/transparent_window"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:background="#android:color/transparent" />
<View
android:id="#+id/black_top_box"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="#id/transparent_window"
android:background="#android:color/background_dark"/>
<View
android:id="#+id/black_bottom_box"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#id/transparent_window"
android:background="#android:color/background_dark"/>
</RelativeLayout>
This solution is one of more of work arounds for your situation. Some code is deprecated and not recommended to use in enterprise projects, but if you need just show a camera preview without squeeze it's enough.
If you need handle image before preview then you should look SurfaceTexture
public class CameraPreview
extends SurfaceView
implements SurfaceHolder.Callback, Camera.PreviewCallback {
public static final String TAG = CameraPreview.class.getSimpleName();
private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
private static final int PREVIEW_SIZE_MAX_WIDTH = 640;
private static final double ASPECT_RATIO = 3.0 / 4.0;
private Camera mCamera;
private SurfaceHolder mHolder;
private boolean mIsLive;
private boolean mIsPreviewing;
public CameraPreview(Context context) {
super(context);
init(context);
}
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int) (width / ASPECT_RATIO + 0.5);
setMeasuredDimension(width, height);
}
#Override
protected void onVisibilityChanged(#NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
//L.g().d(TAG, "onVisibilityChanged: visibility=" + visibility);
if (mIsLive) {
if (visibility == VISIBLE && !mIsPreviewing) {
startCameraPreview();
} else {
stopCameraPreview();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
startCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
stopCamera();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//L.g().d(TAG, "surfaceChanged: format=" + format + ", width=" + w + ", height=" + h);
if (mHolder.getSurface() == null || mCamera == null) return;
mHolder = holder;
try {
mCamera.stopPreview();
} catch (Exception ignored) {}
try {
mCamera.setPreviewDisplay(mHolder);
if (mIsLive && mIsPreviewing) mCamera.startPreview();
} catch (Exception ignored) {}
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
//work with camera preview
if (mIsPreviewing) camera.setOneShotPreviewCallback(this);
}
private Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
return determineBestSize(parameters.getSupportedPreviewSizes(), PREVIEW_SIZE_MAX_WIDTH);
}
private Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
return determineBestSize(parameters.getSupportedPictureSizes(), PICTURE_SIZE_MAX_WIDTH);
}
/**
* This code I found in this repository
* https://github.com/boxme/SquareCamera/blob/master/squarecamera/src/main/java/com/desmond/squarecamera/CameraFragment.java#L368
*/
private Camera.Size determineBestSize(List<Camera.Size> sizes, int widthThreshold) {
Camera.Size bestSize = null;
Camera.Size size;
int numOfSizes = sizes.size();
for (int i = 0; i < numOfSizes; i++) {
size = sizes.get(i);
boolean isDesireRatio = (size.width / 4) == (size.height / 3);
boolean isBetterSize = (bestSize == null) || size.width > bestSize.width;
if (isDesireRatio && isBetterSize) {
bestSize = size;
}
}
if (bestSize == null) {
return sizes.get(sizes.size() - 1);
}
return bestSize;
}
private void init(Context context) {
mHolder = getHolder();
mHolder.addCallback(this);
}
public void startCamera() {
if (!mIsLive) {
//L.g().d(TAG, "startCamera");
mIsPreviewing = false;
mCamera = Camera.open();
if (mCamera != null) {
try {
Camera.Parameters param = mCamera.getParameters();
Camera.Size bestPreviewSize = determineBestPreviewSize(param);
Camera.Size bestPictureSize = determineBestPictureSize(param);
param.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
param.setPictureSize(bestPictureSize.width, bestPictureSize.height);
mCamera.setParameters(param);
} catch (RuntimeException ignored) {}
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewCallback(this);
mCamera.setPreviewDisplay(mHolder);
mIsLive = true;
} catch (Exception ignored) {}
}
//else L.g().d(TAG, "startCamera: error launching the camera");
}
}
public void stopCamera() {
if (mCamera != null && mIsLive) {
//L.g().d(TAG, "stopCamera");
mCamera.stopPreview();
mCamera.release();
mCamera = null;
mIsPreviewing = false;
mIsLive = false;
}
}
public void startCameraPreview() {
if (mCamera != null && mIsLive && !mIsPreviewing) {
//L.g().d(TAG, "startCameraPreview");
mCamera.setPreviewCallback(this);
mCamera.startPreview();
mIsPreviewing = true;
}
}
public void stopCameraPreview() {
if (mCamera != null && mIsLive && mIsPreviewing) {
//L.g().d("stopCameraPreview");
mCamera.stopPreview();
mIsPreviewing = false;
}
}
}
after a lot of looking last few days I believe that I need to post my solution here.
the only that I have managed to do and it working good is to add a scale.
I wanted to create a textureview with a part of the camera output, but I couldn't do that without letting the preview to get scalled.
so after I decide what is the best resolution for the camera/screen ratio to start capturing I get the scale ratio between the camera capture height and the height I want to show.
mPreviewSize = chooseOptimalSize(...);
int viewHeight = getDP(this, R.dimen.videoCaptureHeight);
float scaleY = mPreviewSize.getHeight() / viewHeight;
setScaleY(scaleY);
Assume you have your Rect or RecF here is your calculation
float imageWidth = bitmap.Width;
float imageHeight = bitmap.Height;
float width = yourscreenWidth;
float heigth = yourscreenHeight ;
var W= width / heigth / (imageWidth / imageHeight);
var W2 = rect.Width() / widt * W;
var H = rect.Height() / heigth;
var cropImageWidth = imageWidth * W2 ;
var cropImageHeight = imageHeight * H ;
var cropImageX = (imageWidth - cropImageWidth) / 2;
var cropImageY = (imageHeight - cropImageHeight) / 2;
Bitmap imageCropped = Bitmap.CreateBitmap(bitmap, (int)cropImageX, (int)cropImageY, (int)cropImageWidth, (int)cropImageHeight);
I would like to effectively make a simple digital zoom for the camera preview, so I thought I would simply resize my SurfaceView to be larger than the screen. Other questions (such as 3813049) seem to indicate that this is easy, so I created the sample code below which I expect to let me see only half of the image horizontally (since the SurfaceView is twice as wide as the screen) and have the image only take up half of the screen horizontally. However, running it (when targeted to SDK version 4 on my Thunderbolt with Android 2.2.1) results in being able to see the whole image horizontally while filling the screen horizontally. The SurfaceView appears to behave as intended vertically (when I make it smaller than the screen), but Android won't allow me to make the SurfaceView larger than the screen.
How can I implement a digital zoom? (No, I cannot use Camera.Parameters.setZoom; not only is this not supported by Android 1.6, but different cameras support and implement this differently)
public class MagnifyTestActivity extends Activity implements SurfaceHolder.Callback {
private MagnificationView mPreview;
private SurfaceHolder mHolder;
private Camera mCamera = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreview = new MagnificationView(this);
setContentView(mPreview);
mHolder = mPreview.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public class MagnificationView extends SurfaceView {
public MagnificationView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth()*2;
int height = display.getHeight()/2;
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
mHolder.setFixedSize(w, h);
mCamera.startPreview();
}
}
UPDATE: Based on #Pulkit Sethi's response, it is possible to stretch/magnify the SurfaceView vertically, just not horizontally. To magnify the SurfaceView vertically, simply replace display.getHeight()/2 with display.getHeight()*2 above. Also observe that changing the width doesn't produce any horizontal magnification, either in my code or in Pulkit's.
//Activity class
public class CameraActivity extends Activity implements SurfaceListener {
private static final String TAG = "CameraActivity";
Camera mCamera;
CameraPreview mPreview;
private FrameLayout mCameraPreview;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_camera);
mCamera = getCameraInstance();
mPreview = new CameraPreview(this, mCamera);
mCameraPreview = (FrameLayout) findViewById(R.id.camera_preview);
mCameraPreview.addView(mPreview);
}
#Override
protected void onPause() {
super.onPause();
releaseCamera();
}
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
} catch (Exception e) {
}
return camera;
}
private void releaseCamera() {
if (null != mCamera) {
mCamera.release();
}
mCamera = null;
}
#Override
public void surfaceCreated() {
//Change these mate
int width = 1000;
int height = 1000;
// Set parent window params
getWindow().setLayout(width, height);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
width, height);
mCameraPreview.setLayoutParams(params);
mCameraPreview.requestLayout();
}
}
// Preview class
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
Context mContext;
Camera mCamera;
SurfaceHolder mHolder;
public interface SurfaceListener{
public void surfaceCreated();
}
SurfaceListener listener;
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
listener = (SurfaceListener)mContext;
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
// Required prior 3.0 HC
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
Parameters params = mCamera.getParameters();
//Change parameters here
mCamera.setParameters(params);
mCamera.startPreview();
listener.surfaceCreated();
} catch (Exception e) {
// TODO: handle exception
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
Log.i(TAG, "Surface changed called");
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
mCamera.setDisplayOrientation(90);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
//Layout file
<?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" >
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="300dp"
android:layout_height="400dp"
android:layout_centerHorizontal="true"
android:paddingTop="10dp" >
</FrameLayout>
</RelativeLayout>
You can't make your surfaceView bigger than the screen. That being said there are ways around it.
I found you can adjust the size of the canvas in the SurfaceView, which will allow zooming.
public class DrawingThread extends Thread {
private MagnificationView mainPanel;
private SurfaceHolder surfaceHolder;
private boolean run;
public DrawingThread(SurfaceHolder surface, MagnificationView panel){
surfaceHolder = surface;
mainPanel = panel;
}
public SurfaceHolder getSurfaceHolder(){
return surfaceHolder;
}
public void setRunning (boolean run){
this.run = run;
}
public void run(){
Canvas c;
while (run){
c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder){
mainPanel.OnDraw(c);
}
} finally {
if (c != null){
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
In the MagnificationView class add a method:
public void OnDraw(Canvas canvas){
if (canvas!=null){
canvas.save();
canvas.scale(scaleX,scaleY);
canvas.restore();
}
}
DrawingThread would be a thread you start in in your Activity. Also in your MagnificationView class override the OnTouchEvent to handle your own pinch-zoom (which will modify scaleX & scaleY.
Hope This solves your issue
What you can do is to get the window and set its height:
getWindow().setLayout(1000, 1000);
This makes your window larger than the screen making your root view and consequently your surfaceview, probably contained inside a Framelayout larger than screen.
This worked for me let me know.
The above would work no matter what. What you would want to do is listen for onSurfaceCreated event for your surface view. Then after you have the started the camera view and you are able to calculate size of your widget holding the preview, you would want to change size of the container widget.
The concept is your container widget (probably FrameLayout) wants to grow larger than screen. The screen itself is restricted by the activity so first set size of your window,
then set size of your framelayout (it would always be shrunk to max size of windows, so set accordingly).
I do all this logic after my onSurfaceCreated is finished I have started the preview. I listen for this event in my activity by implementing a small interface, as my Camera preview is a separate class.
Working on all API level >= 8
Here's my TouchSurfaceView's onMeasure that performs zoom:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension((int) (width * scaleFactor), (int) (height * scaleFactor));
}
This properly zooms in and out depending on scaleFactor.
I haven't tested this with camera, but it works properly with MediaPlayer (behaving as VideoView).