This is the first time I am trying to render the Camera Preview using OpenGL ES 2.0. I am into some issues with the code. Here goes the code below --
MainActivity.java
public class MainActivity extends AppCompatActivity implements SurfaceTexture.OnFrameAvailableListener {
private Camera mCamera;
private GLSurfaceView glSurfaceView;
Bitmap bitmap;
FrameLayout frameLayout;
DrawOnTop drawOnTop;
FrameLayout.LayoutParams layoutParams;
private SurfaceTexture surface;
MyGLRenderer renderer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
frameLayout = (FrameLayout)findViewById(R.id.camera_preview);
drawOnTop = null;
}
public void onCamViewButtonClicked (View view)
{
glSurfaceView = new MyGLSurfaceView(this);
renderer = MyGLSurfaceView.getRenderer();
frameLayout.addView(glSurfaceView);
}
public void startCamera(int texture)
{
surface = new SurfaceTexture(texture);
surface.setOnFrameAvailableListener(this);
renderer.setSurface(surface);
mCamera = Camera.open();
try
{
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
public void onFrameAvailable(SurfaceTexture surfaceTexture)
{
glSurfaceView.requestRender();
}
public void onOverlayImageButtonClicked(View view)
{
if(glSurfaceView == null)
{
Toast.makeText(getApplicationContext(),"Preview is not available now!",Toast.LENGTH_LONG).show();
return;
}
else {
if(drawOnTop != null)
{
frameLayout.removeView(drawOnTop);
drawOnTop = null;
}
else
{
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.internetothings);
drawOnTop = new DrawOnTop(this, bitmap);
layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER_HORIZONTAL;
frameLayout.addView(drawOnTop, layoutParams);
Toast.makeText(getApplicationContext(),"Click again to remove!",Toast.LENGTH_LONG).show();
}
}
}
public void onPause()
{
super.onPause();
mCamera.stopPreview();
mCamera.release();
}
}
MyGLSurfaceView.java
public class MyGLSurfaceView extends GLSurfaceView{
static MyGLRenderer myGLRenderer;
public MyGLSurfaceView(Context c)
{
super(c);
setEGLContextClientVersion(2);
myGLRenderer = new MyGLRenderer((MainActivity)c);
setRenderer(myGLRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
public static MyGLRenderer getRenderer()
{
return myGLRenderer;
}
}
MyGLRenderer.java
public class MyGLRenderer implements GLSurfaceView.Renderer{
int texture;
private SurfaceTexture surfaceTexture;
MainActivity mainActivity;
public MyGLRenderer(MainActivity main)
{
mainActivity = main;
}
public void onSurfaceCreated(GL10 unused, javax.microedition.khronos.egl.EGLConfig config)
{
texture = createTexture();
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
mainActivity.startCamera(texture);
}
public void onDrawFrame(GL10 unused)
{
float[] mtx = new float[16];
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
surfaceTexture.updateTexImage();
surfaceTexture.getTransformMatrix(mtx);
}
public void onSurfaceChanged(GL10 unused, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
}
static private int createTexture()
{
int[] texture = new int[1];
GLES20.glGenTextures(1, texture, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
return texture[0];
}
public void setSurface(SurfaceTexture _surface)
{
surfaceTexture = _surface;
}
}
Issue 1: After all this, I am getting a Grey texture instead of a Camera Preview. As a reference I have checked this post. Please help me to identify what went wrong over here.
Issue 2: While investigating Issue 1, I feel (not sure though) that in MyGLSurfaceView.java, declaring myGLRenderer as static could be a problem. Also I have declared the method getRenderer() as static as well which might cause the issue. So I removed the static keyword as below --
public class MyGLSurfaceView extends GLSurfaceView {
MyGLRenderer myGLRenderer;
public MyGLSurfaceView(Context c)
{
super(c);
setEGLContextClientVersion(2);
myGLRenderer = new MyGLRenderer((MainActivity)c);
setRenderer(myGLRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
public MyGLRenderer getRenderer()
{
return myGLRenderer;
}
}
But then I run into a very weird issue in this line --
glSurfaceView = new MyGLSurfaceView(this);
renderer = glSurfaceView.getRenderer();
It says "Cannot resolve method getRenderer()".
Can anybody please help me get over these two issues?
Thanks in advance!
You can try various options:
I had the issue null point exception: MainActivity.startCamera.
First, I would say check your device settings: Settings --> Apps --> (Your App) --> permissions and change it to camera.
Second, you can try changing your startCamera() because we need to release the camera after we performed the event. Modified as follows:
public void startCamera(int texture) {
releaseCameraAndPreview();
surface = new SurfaceTexture(texture);
surface.setOnFrameAvailableListener(this);
renderer.setSurface(surface);
mCamera = Camera.open();
Camera.Parameters parameters = mCamera.getParameters();
mCamera.setParameters(parameters);
try
{
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
}
catch (IOException ioe)
{
Log.w("MainActivity","CAM LAUNCH FAILED");
}
}
just add releaseCameraAndPreview() at the bottom of MainActivity()
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
Try that and let us know. There can be other options too, eg. changing in the manifest file : Add the following
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Hope this helps
Related
I'm trying to build a live wallpaper in Android, but it crashes the app when the orientation changes. It looks like it's crashing when trying to lockCanvas on the surface holder, but I'm not sure what I can do to prevent it.
Here's the class:
public class LiveWallpaperService extends WallpaperService
{
public void onCreate() {
super.onCreate();
}
public void onDestroy() {
super.onDestroy();
}
public Engine onCreateEngine() {
return new MyWallpaperEngine();
}
class MyWallpaperEngine extends Engine
{
private final Handler handler = new Handler();
private final Runnable drawRunner = new Runnable() {
#Override
public void run() {
draw();
}
};
private boolean visible = true;
Paint paint;
MyWallpaperEngine() {
paint = new Paint();
}
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
}
#Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(drawRunner);
}
else {
handler.removeCallbacks(drawRunner);
}
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
this.visible = false;
handler.removeCallbacks(drawRunner);
}
public void onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) {
draw();
}
void draw() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
// Paint stuff here.
}
}
finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
handler.removeCallbacks(drawRunner);
if (visible) {
handler.postDelayed(drawRunner, 10);
}
}
}
}
And this is the exception that happens when the orientation changes:
E/StudioProfiler: JVMTI error: 15(JVMTI_ERROR_THREAD_NOT_ALIVE)
E/Surface: dequeueBuffer failed (No such device)
E/BaseSurfaceHolder: Exception locking surface
java.lang.IllegalArgumentException
at android.view.Surface.nativeLockCanvas(Native Method)
at android.view.Surface.lockCanvas(Surface.java:318)
at com.android.internal.view.BaseSurfaceHolder.internalLockCanvas(BaseSurfaceHolder.java:194)
at com.android.internal.view.BaseSurfaceHolder.lockCanvas(BaseSurfaceHolder.java:158)
at android.service.wallpaper.WallpaperService$Engine$1.lockCanvas(WallpaperService.java:262)
at greencell.bitpatternswallpaper.LiveWallpaperService$MyWallpaperEngine.draw(LiveWallpaperService.java:206)
at greencell.bitpatternswallpaper.LiveWallpaperService$MyWallpaperEngine$1.run(LiveWallpaperService.java:51)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Update:
I've checked many other threads that seem to have the same issue but the only thing that I can do so far is to wrap unlockCanvasAndPost and lockCanvas in a try catch to ignore IllegalArgumentException.
In draw(), I'd try moving handler.removeCallbacks(drawRunner); just before the try block. It could be that onOffsetsChanged() is getting called on orientation change, and that the previous thread on the handler might not have called unlockCanvasAndPost(c) yet, which explains why you're getting an error with lockCanvas() at that point. However, this shouldn't be the case if the code you've posted here exactly matches what you're running locally, since you haven't overriden onOffsetsChanged().
Another thing you could try is overriding onSurfaceChanged() and clearing the handler queue like this:
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
handler.removeCallbacks(drawRunner);
super.onSurfaceChanged(holder, format, width, height);
}
Ultimately, all of the examples regarding WallpaperService that I've read online have a try-finally block with the lock/unlock canvas logic, so I wouldn't be worried.
try android:configChanges="orientation" on your
<service android:name=".LiveWallpaperService" /> in Manifest
example:
<service android:name=".LiveWallpaperService"
android:configChanges="orientation" />
So it is not really desired to do this during oncreate though it is my thought that the animations I want to use will work much better with an image rather than a FrameLayout.
So What I have figured so far is (by reading https://stackoverflow.com/a/4406090/1815624), using ViewTreeObserver I am able to use getHeight in the function shown at the bottom which is where the error occurs where it states view.getWidth(), view.getHeight()
Really I just want to get that image of the view and nuke the original with something like removePieChart(fl); Though as soon I used removePieChart(fl); the errors happen...
A timed event may work but it seems like a bad idea...Any suggestions?
Please and Thanks
protected void onCreate(Bundle savedInstanceState) {
final FrameLayout tv = (FrameLayout)findViewById(R.id.pieChart);
final ViewTreeObserver observer= tv.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
View fl = findViewById(R.id.pieChart);
image.setImageBitmap(viewToBitmap(fl));
removePieChart(fl);
// observer.removeOnGlobalLayoutListener(this);
}
});
}
private void removePieChart(View fl) {
((ViewManager)fl.getParent()).removeView(fl);
}
and for reference here is the viewToBitmap method from https://stackoverflow.com/a/21726101/1815624
public Bitmap viewToBitmap(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
try {
FileOutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory() + "/file.png");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
I recommend using the following class I snatched a while ago from the since-deleted Flow-Sample made by Square:
import android.view.View;
import android.view.ViewTreeObserver;
public final class ViewUtils {
public interface OnMeasuredCallback {
void onMeasured(View view, int width, int height);
}
public static void waitForMeasure(final View view, final OnMeasuredCallback callback) {
int width = view.getWidth();
int height = view.getHeight();
if (width > 0 && height > 0) {
callback.onMeasured(view, width, height);
return;
}
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override public boolean onPreDraw() {
final ViewTreeObserver observer = view.getViewTreeObserver();
if (observer.isAlive()) {
observer.removeOnPreDrawListener(this);
}
callback.onMeasured(view, view.getWidth(), view.getHeight());
return true;
}
});
}
private ViewUtils() {
}
}
Then you use it as
ViewUtils.waitForMeasure(view, new ViewUtils.OnMeasuredCallback() {
public void onMeasured(View view, int width, int height) {
Log.d(TAG, "Do something with height [" + height + "]");
}
});
**Try this code**
final LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
final ViewTreeObserver observer= layout.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
Log.d("Log", "Height: " + layout.getHeight());
}
});
Firstly got to remove the listener addOnGlobalLayoutListener so it stop it from repeatedly calling the removePieChart() method. Once that is done, you can then remove the view.
So onGlobalLayout get's changed :
public void onGlobalLayout() {
View fl = findViewById(R.id.pieChart);
image.setImageBitmap(viewToBitmap(fl));
removePieChart(this); //TODO remove the PieChart resource
}
and also removePieChart() is changed
private void removePieChart(ViewTreeObserver.OnGlobalLayoutListener a) {
final FrameLayout fl = (FrameLayout)findViewById(R.id.pieChart);
final ViewTreeObserver observer= fl.getViewTreeObserver();
observer.removeOnGlobalLayoutListener(a);
((ViewManager)fl.getParent()).removeView(fl);
}
I'm creating a app which has a camera built by myself using camera preview. And it works fine on my Android 4.1 device (the camera opens and takes photos). But when I try on my Android 2.3 device, the app crashes on framelayout.addView(camera_view) because when I comment this line the app doesn't crashes.
Here's my code (the measures are just to fit the device screen):
private void setUpCamera() {
camera_view = new CameraSurfaceView(getApplicationContext());
frame_layout = (FrameLayout) findViewById(R.id.image_frame);
// v it's a square that I draw
v.getLayoutParams().width = (int) ((720/4) + (5*screenDensity));
v.getLayoutParams().height = (int) ((720/4) + (5*screenDensity));
// img it's the imageview where I display the photo
img.getLayoutParams().width = (int) (720/4);
img.getLayoutParams().height = (int) (720/4);
frame_layout.getLayoutParams().width = (int) (720/4);
frame_layout.getLayoutParams().height = (int) (960/4);
frame_layout.addView(camera_view);
}
Here is the camera_view class:
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder m_holder;
public Camera camera = null;
public CameraSurfaceView(Context context) {
super(context);
m_holder = getHolder();
m_holder.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters params = camera.getParameters();
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
camera.setDisplayOrientation(90);
} else {
camera.setDisplayOrientation(0);
}
params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
params.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
params.setExposureCompensation(0);
params.setJpegQuality(100);
List<Size> sizes = params.getSupportedPictureSizes();
Camera.Size size = sizes.get(0);
for(int i=0;i<sizes.size();i++)
{
if(sizes.get(i).width > size.width)
size = sizes.get(i);
}
params.setPreviewSize(size.width, size.height);
params.setPictureSize(size.width, size.height);
camera.setParameters(params);
camera.startPreview();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
try {
camera.setPreviewDisplay(m_holder);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}
public void capture(Camera.PictureCallback jpeghandler){
camera.takePicture(null, null, jpeghandler);
}
}
I have an application that process frames from camera and displayed on a layout, the class that captures and manages the camera frames is like:
package org.opencv.face;
import java.io.IOException;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public abstract class SampleViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private static final String TAG = "Sample::SurfaceView";
public Camera mCamera;
private SurfaceHolder mHolder;
private int mFrameWidth;
private int mFrameHeight;
private byte[] mFrame;
private boolean mThreadRun;
private byte[] mBuffer;
public SampleViewBase(Context context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
Log.i(TAG, "Instantiated new " + this.getClass());
}
public int getFrameWidth() {
return mFrameWidth;
}
public int getFrameHeight() {
return mFrameHeight;
}
public void setPreview() throws IOException {
mCamera.setPreviewDisplay(null);
}
public boolean openCamera() {
Log.i(TAG, "openCamera");
releaseCamera();
mCamera = Camera.open();
if(mCamera == null) {
Log.e(TAG, "Can't open camera!");
return false;
}
mCamera.setPreviewCallbackWithBuffer(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
synchronized (SampleViewBase.this) {
System.arraycopy(data, 0, mFrame, 0, data.length);
SampleViewBase.this.notify();
}
camera.addCallbackBuffer(mBuffer);
}
});
return true;
}
public void releaseCamera() {
Log.i(TAG, "releaseCamera");
mThreadRun = false;
synchronized (this) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
onPreviewStopped();
}
public void setupCamera(int width, int height) {
Log.i(TAG, "setupCamera");
synchronized (this) {
if (mCamera != null) {
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
mFrameWidth = width;
mFrameHeight = height;
// selecting optimal camera preview size
{
int minDiff = Integer.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - height) < minDiff) {
mFrameWidth = size.width;
mFrameHeight = size.height;
minDiff = Math.abs(size.height - height);
}
}
}
params.setPreviewSize(getFrameWidth(), getFrameHeight());
List<String> FocusModes = params.getSupportedFocusModes();
if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
{
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
mCamera.setParameters(params);
/* Now allocate the buffer */
params = mCamera.getParameters();
int size = params.getPreviewSize().width * params.getPreviewSize().height;
size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8 * 2;
mBuffer = new byte[size];
/* The buffer where the current frame will be copied */
mFrame = new byte [size];
mCamera.addCallbackBuffer(mBuffer);
try {
setPreview();
} catch (IOException e) {
Log.e(TAG, "mCamera.setPreviewDisplay/setPreviewTexture fails: " + e);
}
/* Notify that the preview is about to be started and deliver preview size */
onPreviewStarted(params.getPreviewSize().width, params.getPreviewSize().height);
/* Now we can start a preview */
mCamera.startPreview();
}
}
}
public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged");
setupCamera(width, height);
}
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
(new Thread(this)).start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed");
releaseCamera();
}
/* The bitmap returned by this method shall be owned by the child and released in onPreviewStopped() */
protected abstract Bitmap processFrame(byte[] data);
/**
* This method is called when the preview process is being started. It is called before the first frame delivered and processFrame is called
* It is called with the width and height parameters of the preview process. It can be used to prepare the data needed during the frame processing.
* #param previewWidth - the width of the preview frames that will be delivered via processFrame
* #param previewHeight - the height of the preview frames that will be delivered via processFrame
*/
protected abstract void onPreviewStarted(int previewWidtd, int previewHeight);
/**
* This method is called when preview is stopped. When this method is called the preview stopped and all the processing of frames already completed.
* If the Bitmap object returned via processFrame is cached - it is a good time to recycle it.
* Any other resources used during the preview can be released.
*/
protected abstract void onPreviewStopped();
public void run() {
mThreadRun = true;
Log.i(TAG, "Starting processing thread");
while (mThreadRun) {
Bitmap bmp = null;
synchronized (this) {
try {
this.wait();
bmp = processFrame(mFrame);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (bmp != null) {
Canvas canvas = mHolder.lockCanvas();
if (canvas != null) {
canvas.drawBitmap(bmp, (canvas.getWidth() - getFrameWidth()) / 2, (canvas.getHeight() - getFrameHeight()) / 2, null);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
Screen not visualize anything but replacing the method "setPreview ()" with the following:
#TargetApi(11)
public void setPreview() throws IOException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mSf = new SurfaceTexture(10);
mCamera.setPreviewTexture( mSf );
}
else
mCamera.setPreviewDisplay(null);
Now works properly, but only with Android versions above 3.0, and what I want is to work for any version.
How can I fix this?
If you want to receive preview callbacks, you must show preview, using setPreviewDisplay() with non-null argument. The API was designed to force you to show this preview on screen. Any workaround that lets you create a dummy SurfaceView that is never rendered, may not work on some devices or after next upgrade.
Prior to Honeycomb, it was possible to create a preview SurfaceView off screen (so that its position is far to the right), and thus the preview was not displayed. This bug was fixed later.
Luckily, with 3+ you can use setPreviewTexture(), and there is no way the platform can force you to actually show a texture.
I have created a class that extends the Overlay class in Osmdroid (CustomOverlay.java). However, nothing appear on the map after I call the method createMark() on the main activity which make use of CustomOverlay.java. I do not want to use ItemizedOverlay class.
Any idea?
CustomOverlay.java (class that extends Overlay)
public CustomOverlay(Context context) {
super(context);
}
#Override
protected void draw(Canvas canvas, MapView mapView, boolean shadow) {
Point screenPoint = new Point();
mapView.getProjection().toPixels(geoPoint, screenPoint);
super.drawAt(canvas, mapView.getResources().getDrawable(R.drawable.marker), screenPoint.x, screenPoint.y, shadow);
}
}
This is the method I call in the main activity:
private void createMarker() {
List<Overlay> mapOverlays = mMapView.getOverlays();
Overlay c = new CustomOverlay(this);
mapOverlays.add(c);
mMapView.invalidate();
}
Answer:
#Override
protected void draw(Canvas canvas, MapView mapView, boolean shadow) {
Point screenPoint = new Point();
mapView.getProjection().toPixels(geoPoint, screenPoint);
Bitmap marker= BitmapFactory.decodeResource(mapView.getResources(), R.drawable.marker);
canvas.drawBitmap(marker, screenPoint.x, screenPoint.y, null);
}
Here's the skeleton of a customized overlay:
public class MyItemizedOverlay extends ItemizedOverlay<OverlayItem> {
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
public MyItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
}
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
#Override
public int size() {
return mOverlays.size();
}
public void removeAllOverlay() {
mOverlays.clear();
}
public void addOverlay(OverlayItem overlay) {
mOverlays.add(overlay);
populate();
}
}
See the differences? Where is your populate() call?
Hope this helps.