Let me begin with the coding first.
My xml file (relevant part of it) contains this:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:background="#ffffff">
<SurfaceView
android:id="#+id/cameraView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone" />
<LinearLayout
android:id="#+id/layStatus"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<TextView
android:id="#+id/txtStatus"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#90000000"
android:paddingBottom="5dip"
android:paddingTop="5dip"
android:gravity="center_vertical|center_horizontal"
android:textSize="20dip" />
</LinearLayout>
</FrameLayout>
As you can see I've got a basic set up, a frame layout which contains a surfaceview (which has visibility set to gone) and another layout with a simple TextView.
Here is what I have in my activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout);
cameraView = (SurfaceView)findViewById(R.id.cameraView);
surfaceHolder = cameraView.getHolder();
surfaceHolder.addCallback(CompassActivity.this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void btnCameraOnClick(View target) {
cameraView.setVisibility(View.VISIBLE);
}
Starting the camera preview is done in Surface changed, which fires when visibility of the surface changes.
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
txtStatus.setVisibility(View.Visible);
txtStatus.setText("Starting camera");
camera = Camera.open();
if (camera != null){
try {
camera.setDisplayOrientation(90);
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size size = sizes.get(0);
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
camera.setPreviewDisplay(holder);
camera.startPreview();
txtStatis.setVisibility(View.GONE);
} catch (IOException e) {
}
}
}
So what's the problem ? I want to simply display a text while the camera preview starts. To do this, I make the txtStatus visible and set a text to it. When the preview is started, I simply hide it. Well, it doesn't work like this, When I press a button to start camera preview, the UI thread freezes waiting for the preview and my status message is not displayed. How can I fix it ? There is a solution at HERE but I was thinking that maybe there is a simpler one.
Thank you for your time.
Camera start up takes some time - external process shall be started and everything set up. I would speculate, that surface changed callback is executed directly from setVisibility() and blocks UI thread. Solution is pretty simple - just spawn new thread and do camera init there.
In my OCR applicatios I start camera in onResume() - since I always need working preview
You may find my OCR android demos helpful:
http://sourceforge.net/projects/javaocr/
( camera preview, with overlays )
Related
What I want is when I scroll up the scrollview the gallery should be open and when I scroll down then the surfaceview(camera) should be visible like OLX. I have explained my requirement in the image.hope I explained my question in proper manner.
I have explained my requirement in this image
im also posting my xml codes to let you properly understand.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
tools:context="com.example.ali.ansofexperts.Question_Photo">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/camera_preview">
</FrameLayout>
<ScrollView
android:layout_width="fill_parent"
android:id="#+id/scrollView"
android:fillViewport="true"
android:layout_height="fill_parent"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:layout_width="fill_parent"
android:minHeight="400dp"
android:layout_height="wrap_content"
android:id="#+id/click"
android:orientation="horizontal">
</LinearLayout>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:columnWidth="90dp"
android:numColumns="auto_fit" android:verticalSpacing="10dp"
android:horizontalSpacing="10dp" android:stretchMode="columnWidth"
android:gravity="center" android:layout_gravity="bottom"
android:layout_marginTop="400dp"></GridView>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
I am posting this Reference for beginner
https://android-arsenal.com/details/1/5987
This Reference have the complete solution about my question,hope this will helpful.
Try this
/** 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();
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.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "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(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
Refer this document you can achieve surfaceview with camer...gallery
party you can try your self..
https://developer.android.com/guide/topics/media/camera.html
https://github.com/googlesamples/android-Camera2Video
So, I'm trying to make a login activity with the camera feed as the background. I've tested the example on https://developer.xamarin.com/guides/android/user_interface/textureview/ and got it to work, but I need to it to be part of an activity. So, I tried this:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.Login);
_textureView = this.FindViewById<TextureView>(Resource.Id.textureView);
_textureView.SurfaceTextureListener = this;
}
public void OnSurfaceTextureAvailable(
Android.Graphics.SurfaceTexture surface, int w, int h)
{
_cam = Camera.Open();
_textureView.LayoutParameters =
new FrameLayout.LayoutParams(w, h);
try
{
_cam.SetPreviewTexture(surface);
_cam.StartPreview();
}
catch (Java.IO.IOException ex)
{
Console.WriteLine(ex.Message);
}
}
The axml file looks somewhat like this:
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView
android:id="#+id/textureView"
android:layout_width="match_parent"
android:layout_height="match_parent"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="SizeProportional" />
<LinearLayout
android:id="#+id/linearLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="SizeProportional">
<!-- Some other controls -->
</LinearLayout>
</AbsoluteLayout>
However, the app now crashes after exiting the OnSurfaceTextureAvailable block, giving an unhandled exception. Breaking at the exception doesn't work, it's apparently in a thread that's not running anymore.
Would anyone know why it crashes and, more importantly, how to fix it?
Problem is with this code:
_textureView.LayoutParameters = new FrameLayout.LayoutParams(w, h);
I'm not sure why your need to reset the TextureView's layout parameters, in xml you've set it to match parent. And the parent here is AbsoluteLayout, not FrameLayout, that's why this error happens.
To solve this issue, since AbsoluteLayout is obsolete now, I suggest to use RelativeLayout as root container in your xml. Then you can code like this:
_textureView.LayoutParameters = new RelativeLayout.LayoutParams(width, height);
Of course you can also change AbsoluteLayout to FrameLayout in your xml, then the code _textureView.LayoutParameters = new FrameLayout.LayoutParams(w, h); doesn't need to be modified anymore.
I'm new on Android, and i trying to build a camera app.
I build an Camera Preview which extends SurfaceView and implements SurfaceHolder.Callback for previewing the camera on the Camera Activity.
here is the contractor :
public CameraPreview(Context context) {
super(context);
mContext = context;
mStartRequested = false;
mSurfaceAvailable = false;
mCamera = null;
mHolder = getHolder();
mHolder.addCallback(this);
}
and the onCreate(in CameraActivity.java) method which initialize the layout:
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_camera);
mPreview = new CameraPreview(this);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
and finally the Layout XML :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="#+id/button"
android:layout_gravity="center_horizontal|bottom" />
</FrameLayout>
</LinearLayout>
AndroidMainifest.xml:
<application
...
android:theme="#android:style/Theme.Holo.Light.NoActionBar.Fullscreen" >
As you can see i tried to add a button on the camera preview but i cant see the button when the app is lunching.
can anyone see the mistake??
Thanks you !
The preview is probably on top of the button (in the Z-order). This line:
preview.addView(mPreview);
adds the CameraPreview to the end of the FrameLayout's internal list of child views. A FrameLayout renders its child views in order; as such, the preview is being drawn after the button, or "over" it. Try this instead:
preview.addView(mPreview, 0);
You can also order your CameraPreview by having it inflate from the XML instead, by using a tag with the fully qualified class name, like this:
<com.yourdomain.CameraPreview
.../>
...although you will need to override the View(Context context, AttributeSet attrs); constructor to make that work.
So I've done a lot of searching but still can't seem to find the exact reason as to why my SurfaceView won't display. Here's a little background as to what I'm doing:
I have a Linear Layout that is set Horizontally. It contains an ImageView, then a vertical Linear Layout, and finally another ImageView. In the vertical Linear Layout, there are essential three things: another ImageView at the top, an extended SurfaceView (called MagnetView) and an ImageView below that.
Here's the xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<!-- Left Magnetrak -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/vectorparts_01"
android:adjustViewBounds="true" />
<!-- Middle Linear Layout -->
<LinearLayout
android:layout_width="0dip"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_weight="1">
<!-- Top Bar with Lifes and Score counter -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true">
<ImageView
android:adjustViewBounds="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/vectorparts_22"/>
<!-- Score counter -->
<TextView
android:id="#+id/myImageViewText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_marginTop="5dp"
android:gravity="center"
android:text="000000000000"
android:textColor="#000000" />
<!-- Life1 -->
<ImageView
android:id = "#+id/life1"
android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/vectorparts_13"
android:layout_alignParentLeft="true"
android:layout_marginLeft="5dp"
android:layout_marginTop="1dp"
android:gravity="center" />
<!-- Life2 -->
<ImageView
android:id = "#+id/life2"
android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/vectorparts_13"
android:layout_toRightOf="#id/life1"
android:layout_marginTop="1dp"
android:layout_marginLeft="1dp"
android:gravity="center" />
<!-- Life3 -->
<ImageView
android:id = "#+id/life3"
android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/vectorparts_13"
android:layout_toRightOf="#id/life2"
android:layout_marginTop="1dp"
android:layout_marginLeft="1dp"
android:gravity="center" />
</RelativeLayout>
<!-- SurfaceView -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/middlesurface">
</LinearLayout>
<!-- Bottom Bar -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true">
<ImageView
android:adjustViewBounds="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/vectorparts_02"/>
</RelativeLayout>
</LinearLayout>
<!-- Right Magnetrak -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/vectorparts_01"
android:adjustViewBounds="true" />
Essentially, I want the MagnetView to show through (or punch a hole) where I put it in the Layout. But it does not display. In fact, the only time my SurfaceView displays is when I set the activity's setContentView() to the SurfaceView explicitly, canceling out everything else.
Here is the actually Activity:
public class Magnetraks extends Activity {
MagnetView midSurf;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
midSurf = new MagnetView(this);
LinearLayout midLL = new LinearLayout(this);
midLL.findViewById(R.id.middlesurface);
midLL.addView(midSurf);
setContentView(R.layout.main);
//Debugging purposes: run to see if middleSurface view is showing up when on its own.
//setContentView(midSurf);
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
midSurf.resume();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
midSurf.pause();
}
Should I place the SurfaceView at the top of my layout xml? Are there more attributes I must set?
Can I just overlay the SurfaceView over everything else, make it translucent and draw what I need? Any help would be greatly appreciated, as I cannot seem to grasp how SurfaceViews work. It seems they are apart of my View hierarchy, but then documentation tells me they are something different entirely.
Thank you.
EDIT 04/17/2012
To offer a little more info:
My xml UI Designer shows a big box in the middle for my extended SurfaceView class, called MagnetView. I've outlined it in red. (Stackoverflow won't allow me to post images yet)
UI Designer view(http://24.media.tumblr.com/tumblr_m2mmqvBNwW1qcreoco1_500.jpg)
http://24.media.tumblr.com/tumblr_m2mmqvBNwW1qcreoco1_500.jpg
Here's the MagnetView (SurfaceView) class:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MagnetView extends SurfaceView implements Runnable, SurfaceHolder.Callback{
Thread mThread;
SurfaceHolder mSurfaceHolder;
volatile boolean running = false;
//Creates new surface view as well as a new surfaceholder, which allows access to the surface
public MagnetView (Context context){
super(context);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
//this.setZOrderOnTop(true);
//getHolder().setFormat(PixelFormat.TRANSLUCENT);
}
public void resume(){
running = true;
mThread = new Thread(this);
mThread.start();
}
public void pause(){
boolean retry = true;
running = false;
while(retry){
try {
mThread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public void run() {
// TODO Auto-generated method stub
while(running){
if(mSurfaceHolder.getSurface().isValid()){
Canvas canvas = mSurfaceHolder.lockCanvas();
//... actual drawing on canvas
canvas.drawARGB(100, 255, 255, 80);
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
this.resume();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
}
I am just putting down the changes.
Replace surface view in the xml with LinearLayout.
<LinearLayout
android:id="#+id/middleSurface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
Get an instance of linear layout
LinearLayout surface = (LinearLayout)findViewById(R.id.surface);
Add the surface view's instance to LinearLayout
surface.addView(new MagnetView(this));
2,3 steps should be performed after setContentView(R.layout.main);
I would examine the layout in the Eclipse UI designer to see if everything is placed as you want to. Surface Views are just ordinary views in regards to layout.
If I am not wrong, the way I perceived your query is: You want something to be displayed/rendered on top of the surface view along with the other view elements as you mentioned in the xml.
If you want a view on top of surface view, you need to extend it(AFAIK there is no other way). Then you need to override the onDraw() method to display what all things you want on the surface view. You also need to get an object of SurfaceHolder which gets the canvas.
Here is a good link showing, putting an imageview on top of surface view:
http://www.droidnova.com/playing-with-graphics-in-android-part-ii,160.html
Remove the surface view from the xml and place a linearlayout in place of that and associate an id with it.
Get an instance of linearlayout.
add child view i.e., magnet view in this case to the linearlayout using
addView()
This solved the problem.
Have you set the background of the SurfaceView? I found that if you set the background of the SurfaceView, it will not display what you draw on the secondary thread.
You could try this other way, move setContentView(R.layout.main); after super.onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
midSurf = new MagnetView(this);
LinearLayout midLL = new LinearLayout(this);
midLL.findViewById(R.id.middlesurface);
midLL.addView(midSurf);
I'm trying to put a camera preview (SurfaceView) together with a button on the display, but all I get is a blank screen only showing the button. If I'm setting the SurfaceView as the only content (with setContentView(surfaceView) then the preview is displaying fine on the screen. What am I doing wrong?
Thanks in advance
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="0px"
android:layout_weight="1">
<SurfaceView
android:id="#+id/camera_surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/trigger"
android:id="#+id/trigger_picture_button"
android:layout_gravity="bottom" />
</FrameLayout>
</LinearLayout>
My Activity:
public class CameraActivity extends Activity {
private SurfaceView cameraPreview;
private Button triggerPicture;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera);
cameraPreview = (SurfaceView) findViewById(R.id.camera_surface);
triggerPicture = (Button) findViewById(R.id.trigger_picture_button);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
cameraPreview = new CameraPreview(this);
// setContentView(cameraPreview);
}
My CameraPreview:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private Camera camera;
public CameraPreview(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
camera = openFrontFacingCamera();
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
camera.release();
camera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(width, height);
parameters.set("orientation", "portrait");
camera.setParameters(parameters);
camera.startPreview();
}
private Camera openFrontFacingCamera() {
// returns Camera.open(
}
When you declare SurfaceView in the layout you tell Android to use built-in class. What you need to do is make it use your class by replacing SurfaceView in XML with your.package.name.CameraPreview.
One other thing: you should add a constructor to the CameraPreview taking parameters Context and AttributeSet, otherwise layout inflater won't be able to inflate your class. Also you don't need the line cameraPreview = new CameraPreview(this);.
When your onCreate() is the right one, than you overriding the cameraPreview from the xml with a new created one which you never add to any layout (last line). That means its never inflated so there is never a surface created.
Maybe it's a bit late answer ,but it really works for me.
1、set the layout as below:
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
/>
<Button
android:id="#+id/button_capture"
android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
2、In onCreate:
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
3、And in Manifest.xml:
android:screenOrientation="landscape"
, of course , don't forget permissions and features.
Hope it helps.