Android native question - Button positing with device scaling

Joshua, you are the man.

A friend was testing the mockup yesterday and he complained about the camera making him thinner. It was basically what you mentioned above, the CameraPreview being used on full screen and not on its original aspect radio.

Thanks man.

Hi Joshua.

As you instructed, I tried to build the Corona Camera Sample app without the permission but when I ran the app on my Android, it shows me the text “Camera not available”. (Didn’t use CoronaCards or Enterprise)

Now, using CoronaCards, for some reason, I am not being grant access to the Camera, even with me requesting them in the AndroidManifest.xml

I created a new thread about it (http://forums.coronalabs.com/topic/47441-not-accessing-camera-on-android/)

Do you have any ideas of what it may be?

I also tried adding the camera permissions to the build.settings (Corona code) and also even tried deleting the build.settings file (I don’t know if it would create conflict with the native AndroidManifest.xml), but both attempts algo gave the same error (Camera not accessible).

UPDATE: I solved the problem of the permission. It was my fault.

Regarding using Corona’s built-in CameraActivity/CameraView, you have to remove the WRITE_EXTERNAL_STORAGE permission.  Without this permission, there would be no means for Corona to access the photo from the device’s default camera app.  You are still required to use the CAMERA permission or else Android won’t allow your application to access the camera at all.

Regarding Corona Cards, I’m not the developer for it, but my understanding is that it can’t support the camera because it would require access to the Activity.onActivityResult() method to know if a photo was taken or not and where the photo was saved to, and the CoronaView does not have access to the activity.  That is, on Android, only an activity can perform this operation, not a view.

Now, Corona Enterprise can definitely support the camera because you would use our CoronaActivity class instead of the CoronaView, which does have access to the onActivityResult() method.  I’m quite positive that this would work.  You can modify one of our Corona Enterprise sample projects to do exactly this quite easily.

Thanks.

About CoronaCards, I am trying to use it only for showing the Camera. I would use Corona display.captureBounds to “take the photo”. So, maybe it would work…  I fixed the permission problem to get the Camera, but now I reached a point where the app is not wanting to create the SurfaceHolder for the CameraPreview.  It appears something related to UI/background threads…  ( Log: "Runtime error 05-01 18:47:07.078: I/Corona(14334): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare() )

Still investigating it…  

You can try using our hidden CameraView.java class that I mentioned up above instead.  It would be a lot easier than trying to implement it yourself.  Seriously, it took me about a week to get it just right when I implemented over 2 years ago.  Trying to handle this natively, especially for all Android versions and across all devices handling different camera mounting orientations is not as simple as it looks.

I believe the Eclipse and Android Studio IDEs should show you all of the hidden methods available in our CamerView Java class via reflection.

Actually, I already created my CameraPreview class and it is working fine. I agree, handling the camera orientation and setting the correct aspect ratio took some work for me also.

My situation is: need to create an app that takes a photo and uploads it to server. Simple as that. The “problem” is that the camera needs to show a frame above the camera view, so I need to access the camera from inside the app and not simply redirects the user to the default camera app.

I already made a Android native code that does that. But I was trying to use the Corona code that I made for the iOS version, since Corona handles the different devices screen in a much better way. In addition, the corona code is running much more smooth than the Android code.

So I tried yesterday and today to use CoronaCards. My ideia was: I show the camera in a view and show the CoronaCards above that view. Finally made CoronaCords work today and now I reached the point that the Camera don’t show up. I am giving up, I will go all natively (unfortunately).

I would glad try to use Corona Enterprise and play around even trying to make the camera fill shape for Android, but I am afraid I would not have enough time to learn CoronaEnterprise integration in the short time available before the deadline.

Thanks for the help.

I see.  Well, Corona Enterprise for Android effectively provides the same class framework as Corona Cards.  In fact, I’m pretty sure that our CoronaActivity Java class is available in Corona Cards, but I can understand if you don’t have time to switch to that.

There are definitely some pluses and minuses between Corona Enterprise and Corona Cards.  The biggest advantage with Corona Enterprise is that it provides a CoronaActivity which has access to *all* features, but you are limited to one instance of the Corona runtime at a time.

Corona Cards allows you to run multiple instances of Corona at the same time and display them as resizable views, but since they don’t have access to the activity, the features they can provide is limited.  But, you’re still able to use Corona’s primary features such as rendering and audio, which is what Corona is mostly used for.

Hi Joshua.

I finished developing the app using native (Java) and I still have 2 weeks to deliver it, so I decided to learn how to use Corona Enterprise and maybe create a plugin to access the android camera.

I already learned the basics here and I am successfully building my “own camera plugin” using my CameraPreview class. (Later I will try to use the Corona built-in CameraView). 

The app is running fine for 1 little thing that I think maybe you may know what it is.

My plugin is simple:   plugin.show()  to show the camera inside the app (taking the maximum screen while keeping aspect ratio) and plugin.hide() to hide the camera view.  Both are working fine.

The problem is: When I first open the app and call the plugin.show(), nothing is displayed. But if the app is suspended and then resumed, the camera will start to show normally.

I was thinking if that problem may be to caused due to some layout z-position.  What do you think?  Is there any trick regarding View position that we may be aware of?

PS: I am adding my camera view (mPreview) to the screen using:

getParent().addView(mPreview);

If your camera preview derives from Android’s SurfaceView, then you will indeed run into some quirky/buggy z-ordering issues with it.  You see, it’s a view that is rendered on a separate thread and the Android OS has a bad habit of rendering too soon or too late, making it render in what appears to be in the wrong z-order.  Google offers some APIs to help work-around this behavior via their setZOrderMediaOverlay() and setZOrderOnTop() methods.

   http://developer.android.com/reference/android/view/SurfaceView.html#setZOrderMediaOverlay(boolean

But that said, I’m not sure if that’s the appropriate solution or not.  Especially since the GLSurfaceView that Corona renders to is a threaded SurfaceView as well.  Your camera preview and our OpenGL view *might* render at the wrong order, even though the z-order within the activity is correct.  You’ll have to experiment with it on your end.

One more thing.  You’re expected to add your view to the layout returned from the CoronaActivity.getOverlayView() method.  This ensures that your view is always on top of Corona’s view (ie: our GLSurfaceView and any views you’ve created via the native APIs), but also puts your view behind the splashscreen view if your app has any Default.png files in it (probably not, but just in case).

Perfect. I will try both (using the z functions and also using the getOverlayView). Thanks!

Using

mPreview.setZOrderMediaOverlay(true);

right after adding the mPreview to the getOverlayView() solved. Thanks Joshua. Now I just need to check if that will make it to stay on top of everything or not (I want to add some images over the camera view).

PS: I was adding my view to getParent() because that is how it is instructed in the ads-provider sample project ("// TODO: Insert call to display new ad. You should add it as a child of ‘getParent()’."). Maybe you would want to update that info there.

Great!  I’m glad you’ve got it working.  You might also want to double check that your camera preview is still being displayed correctly when suspending/resuming your app via the Home key and via the Power button.  That’s when those threaded SurfaceViews tend to render in the wrong z-order on you.  But hopefully that setZOrderMediaOverlay() method takes care of it in those cases too.

 

Hi Josua. Sorry to bother you again. I searched a lot and didn’t find information about a very simple thing.

How can I get access to a Android View (that to the getOverlayView()) on my Corona code? (like to change its position)

On Android, you set the position of your view via LayoutParams that you pass into the container.  How you position it depends on the layout container.  Corona’s overlay view is a FrameLayout which allows you to “stack” views on top of each other so that one view does not affect the position of another view.  The idea here is to allow a Corona plugin to display a native Android view without affecting the position of other views created by other plugins.

In your case, I suppose you want to set your view to a specific (x,y) pixel position, right?  So, in my opinion, the best solution is to create your own AbsoluteLayout to be a container for your camera preview, and you would add your AbsoluteLayout to Corona’s overlay view fullscreen.  You would then use the AbsoluteLayout.LayoutParams inner class to position your camera preview.  You would set these params when you call addView() in the container… and when moving your camera preview, you would call the view’s setLayoutParams() method with a new instance of AbsoluteLayout.LayoutParams set to a new x/y width/height.

Thanks for the info Joshua.

Actually, my case is: I want to have a corona display object (image) in front of the camera preview that I added natively and then take a snapshot of it.

I spent the whole weekend going thru the insides of the Corona library and my conclusion is that this is not possible (or am I wrong?).

For what I understood (and for future users reference), Corona Enterprises creates the following view structure for an Android app

1. myContentView 1.1 glView (surfaceview that has all the corona objects) 1.2 mOverlayView 1.3 myAbsolutePopupLayout

So, it is impossible to have an object that is inside the glView (which would be my image) to be in front of the mOverlayView (which holds the camera preview).

I tried to move the whole glView to be in front of the mOverlayView (making the glView to have transparent background), but it didn’t work.

So, for what I see, it is impossible to create a plugin using Corona Enterprise that shows the camera inside of a Corona app in way that you can control the camera object as it were a display object (which is what we can do today using the shape camera fill on iOS), am I right?

What you’re trying to do isn’t going to work.  Corona’s display objects are rendered in OpenGL in the GLSurfaceView *behind* your Camera preview view.  If you want to display an image on top, then you’ll have to use an Android’s “ImageView” class instead.  You can’t render it in OpenGL.

Yeah, I noticed that. Very frustrating…

So, if you would implement a iOS camera fill type for Android, what would you do? You would have to do it using NDK?

Corona does not give you the ability render your own custom content in OpenGL via native APIs.  And we’re not planning on adding a camera fill on Android in the near future.  So, you’re only option is to change your design and display native Android views on top of the camera preview.

I know that you guys are not planing to camera fill for Android, that why I am trying to create some work around for it.

Thanks for all the explanations Joshua.

Using an Android ImageView is relatively straight forward.  If you want to use your Corona projects existing image files in the Android project’s Assets directory, then you can easily load it via our FileServices class.  If you call that class’ openFile() method with a relative path, then it’ll default to the Assets directory… or a Google Expansion file if applicable.

   http://docs.coronalabs.com/native/android/html/com/ansca/corona/storage/FileServices.html

Once you’ve opened the file, you would then pass the returned stream to Android’s BitmapFactory.decodeStream() method to decode the image to a raw bitmap.

   http://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeStream(java.io.InputStream

The above will return a Java bitmap object (if successfully decoded) which you can pass into an ImageView class’ setImageBitmap() method.

   http://developer.android.com/reference/android/widget/ImageView.html#setImageBitmap(android.graphics.Bitmap